##// END OF EJS Templates
revset: fix ancestors(null) to include null revision (issue4512)...
Yuya Nishihara -
r23956:b1e026c2 stable
parent child Browse files
Show More
@@ -1,3288 +1,3288 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, discovery, hbisect, phases
9 import parser, util, error, discovery, 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 cut = followfirst and 1 or None
21 cut = followfirst and 1 or None
22 cl = repo.changelog
22 cl = repo.changelog
23
23
24 def iterate():
24 def iterate():
25 revqueue, revsnode = None, None
25 revqueue, revsnode = None, None
26 h = []
26 h = []
27
27
28 revs.sort(reverse=True)
28 revs.sort(reverse=True)
29 revqueue = util.deque(revs)
29 revqueue = util.deque(revs)
30 if revqueue:
30 if revqueue:
31 revsnode = revqueue.popleft()
31 revsnode = revqueue.popleft()
32 heapq.heappush(h, -revsnode)
32 heapq.heappush(h, -revsnode)
33
33
34 seen = set([node.nullrev])
34 seen = set()
35 while h:
35 while h:
36 current = -heapq.heappop(h)
36 current = -heapq.heappop(h)
37 if current not in seen:
37 if current not in seen:
38 if revsnode and current == revsnode:
38 if revsnode and current == revsnode:
39 if revqueue:
39 if revqueue:
40 revsnode = revqueue.popleft()
40 revsnode = revqueue.popleft()
41 heapq.heappush(h, -revsnode)
41 heapq.heappush(h, -revsnode)
42 seen.add(current)
42 seen.add(current)
43 yield current
43 yield current
44 for parent in cl.parentrevs(current)[:cut]:
44 for parent in cl.parentrevs(current)[:cut]:
45 if parent != node.nullrev:
45 if parent != node.nullrev:
46 heapq.heappush(h, -parent)
46 heapq.heappush(h, -parent)
47
47
48 return generatorset(iterate(), iterasc=False)
48 return generatorset(iterate(), iterasc=False)
49
49
50 def _revdescendants(repo, revs, followfirst):
50 def _revdescendants(repo, revs, followfirst):
51 """Like revlog.descendants() but supports followfirst."""
51 """Like revlog.descendants() but supports followfirst."""
52 cut = followfirst and 1 or None
52 cut = followfirst and 1 or None
53
53
54 def iterate():
54 def iterate():
55 cl = repo.changelog
55 cl = repo.changelog
56 first = min(revs)
56 first = min(revs)
57 nullrev = node.nullrev
57 nullrev = node.nullrev
58 if first == nullrev:
58 if first == nullrev:
59 # Are there nodes with a null first parent and a non-null
59 # Are there nodes with a null first parent and a non-null
60 # second one? Maybe. Do we care? Probably not.
60 # second one? Maybe. Do we care? Probably not.
61 for i in cl:
61 for i in cl:
62 yield i
62 yield i
63 else:
63 else:
64 seen = set(revs)
64 seen = set(revs)
65 for i in cl.revs(first + 1):
65 for i in cl.revs(first + 1):
66 for x in cl.parentrevs(i)[:cut]:
66 for x in cl.parentrevs(i)[:cut]:
67 if x != nullrev and x in seen:
67 if x != nullrev and x in seen:
68 seen.add(i)
68 seen.add(i)
69 yield i
69 yield i
70 break
70 break
71
71
72 return generatorset(iterate(), iterasc=True)
72 return generatorset(iterate(), iterasc=True)
73
73
74 def _revsbetween(repo, roots, heads):
74 def _revsbetween(repo, roots, heads):
75 """Return all paths between roots and heads, inclusive of both endpoint
75 """Return all paths between roots and heads, inclusive of both endpoint
76 sets."""
76 sets."""
77 if not roots:
77 if not roots:
78 return baseset()
78 return baseset()
79 parentrevs = repo.changelog.parentrevs
79 parentrevs = repo.changelog.parentrevs
80 visit = list(heads)
80 visit = list(heads)
81 reachable = set()
81 reachable = set()
82 seen = {}
82 seen = {}
83 minroot = min(roots)
83 minroot = min(roots)
84 roots = set(roots)
84 roots = set(roots)
85 # open-code the post-order traversal due to the tiny size of
85 # open-code the post-order traversal due to the tiny size of
86 # sys.getrecursionlimit()
86 # sys.getrecursionlimit()
87 while visit:
87 while visit:
88 rev = visit.pop()
88 rev = visit.pop()
89 if rev in roots:
89 if rev in roots:
90 reachable.add(rev)
90 reachable.add(rev)
91 parents = parentrevs(rev)
91 parents = parentrevs(rev)
92 seen[rev] = parents
92 seen[rev] = parents
93 for parent in parents:
93 for parent in parents:
94 if parent >= minroot and parent not in seen:
94 if parent >= minroot and parent not in seen:
95 visit.append(parent)
95 visit.append(parent)
96 if not reachable:
96 if not reachable:
97 return baseset()
97 return baseset()
98 for rev in sorted(seen):
98 for rev in sorted(seen):
99 for parent in seen[rev]:
99 for parent in seen[rev]:
100 if parent in reachable:
100 if parent in reachable:
101 reachable.add(rev)
101 reachable.add(rev)
102 return baseset(sorted(reachable))
102 return baseset(sorted(reachable))
103
103
104 elements = {
104 elements = {
105 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
105 "(": (21, ("group", 1, ")"), ("func", 1, ")")),
106 "##": (20, None, ("_concat", 20)),
106 "##": (20, None, ("_concat", 20)),
107 "~": (18, None, ("ancestor", 18)),
107 "~": (18, None, ("ancestor", 18)),
108 "^": (18, None, ("parent", 18), ("parentpost", 18)),
108 "^": (18, None, ("parent", 18), ("parentpost", 18)),
109 "-": (5, ("negate", 19), ("minus", 5)),
109 "-": (5, ("negate", 19), ("minus", 5)),
110 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
110 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
111 ("dagrangepost", 17)),
111 ("dagrangepost", 17)),
112 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
112 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
113 ("dagrangepost", 17)),
113 ("dagrangepost", 17)),
114 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
114 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
115 "not": (10, ("not", 10)),
115 "not": (10, ("not", 10)),
116 "!": (10, ("not", 10)),
116 "!": (10, ("not", 10)),
117 "and": (5, None, ("and", 5)),
117 "and": (5, None, ("and", 5)),
118 "&": (5, None, ("and", 5)),
118 "&": (5, None, ("and", 5)),
119 "%": (5, None, ("only", 5), ("onlypost", 5)),
119 "%": (5, None, ("only", 5), ("onlypost", 5)),
120 "or": (4, None, ("or", 4)),
120 "or": (4, None, ("or", 4)),
121 "|": (4, None, ("or", 4)),
121 "|": (4, None, ("or", 4)),
122 "+": (4, None, ("or", 4)),
122 "+": (4, None, ("or", 4)),
123 ",": (2, None, ("list", 2)),
123 ",": (2, None, ("list", 2)),
124 ")": (0, None, None),
124 ")": (0, None, None),
125 "symbol": (0, ("symbol",), None),
125 "symbol": (0, ("symbol",), None),
126 "string": (0, ("string",), None),
126 "string": (0, ("string",), None),
127 "end": (0, None, None),
127 "end": (0, None, None),
128 }
128 }
129
129
130 keywords = set(['and', 'or', 'not'])
130 keywords = set(['and', 'or', 'not'])
131
131
132 # default set of valid characters for the initial letter of symbols
132 # default set of valid characters for the initial letter of symbols
133 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
133 _syminitletters = set(c for c in [chr(i) for i in xrange(256)]
134 if c.isalnum() or c in '._@' or ord(c) > 127)
134 if c.isalnum() or c in '._@' or ord(c) > 127)
135
135
136 # default set of valid characters for non-initial letters of symbols
136 # default set of valid characters for non-initial letters of symbols
137 _symletters = set(c for c in [chr(i) for i in xrange(256)]
137 _symletters = set(c for c in [chr(i) for i in xrange(256)]
138 if c.isalnum() or c in '-._/@' or ord(c) > 127)
138 if c.isalnum() or c in '-._/@' or ord(c) > 127)
139
139
140 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
140 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
141 '''
141 '''
142 Parse a revset statement into a stream of tokens
142 Parse a revset statement into a stream of tokens
143
143
144 ``syminitletters`` is the set of valid characters for the initial
144 ``syminitletters`` is the set of valid characters for the initial
145 letter of symbols.
145 letter of symbols.
146
146
147 By default, character ``c`` is recognized as valid for initial
147 By default, character ``c`` is recognized as valid for initial
148 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
148 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
149
149
150 ``symletters`` is the set of valid characters for non-initial
150 ``symletters`` is the set of valid characters for non-initial
151 letters of symbols.
151 letters of symbols.
152
152
153 By default, character ``c`` is recognized as valid for non-initial
153 By default, character ``c`` is recognized as valid for non-initial
154 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
154 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
155
155
156 Check that @ is a valid unquoted token character (issue3686):
156 Check that @ is a valid unquoted token character (issue3686):
157 >>> list(tokenize("@::"))
157 >>> list(tokenize("@::"))
158 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
158 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
159
159
160 '''
160 '''
161 if syminitletters is None:
161 if syminitletters is None:
162 syminitletters = _syminitletters
162 syminitletters = _syminitletters
163 if symletters is None:
163 if symletters is None:
164 symletters = _symletters
164 symletters = _symletters
165
165
166 pos, l = 0, len(program)
166 pos, l = 0, len(program)
167 while pos < l:
167 while pos < l:
168 c = program[pos]
168 c = program[pos]
169 if c.isspace(): # skip inter-token whitespace
169 if c.isspace(): # skip inter-token whitespace
170 pass
170 pass
171 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
171 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
172 yield ('::', None, pos)
172 yield ('::', None, pos)
173 pos += 1 # skip ahead
173 pos += 1 # skip ahead
174 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
174 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
175 yield ('..', None, pos)
175 yield ('..', None, pos)
176 pos += 1 # skip ahead
176 pos += 1 # skip ahead
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 in "():,-|&+!~^%": # handle simple operators
180 elif c in "():,-|&+!~^%": # handle simple operators
181 yield (c, None, pos)
181 yield (c, None, pos)
182 elif (c in '"\'' or c == 'r' and
182 elif (c in '"\'' or c == 'r' and
183 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
183 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
184 if c == 'r':
184 if c == 'r':
185 pos += 1
185 pos += 1
186 c = program[pos]
186 c = program[pos]
187 decode = lambda x: x
187 decode = lambda x: x
188 else:
188 else:
189 decode = lambda x: x.decode('string-escape')
189 decode = lambda x: x.decode('string-escape')
190 pos += 1
190 pos += 1
191 s = pos
191 s = pos
192 while pos < l: # find closing quote
192 while pos < l: # find closing quote
193 d = program[pos]
193 d = program[pos]
194 if d == '\\': # skip over escaped characters
194 if d == '\\': # skip over escaped characters
195 pos += 2
195 pos += 2
196 continue
196 continue
197 if d == c:
197 if d == c:
198 yield ('string', decode(program[s:pos]), s)
198 yield ('string', decode(program[s:pos]), s)
199 break
199 break
200 pos += 1
200 pos += 1
201 else:
201 else:
202 raise error.ParseError(_("unterminated string"), s)
202 raise error.ParseError(_("unterminated string"), s)
203 # gather up a symbol/keyword
203 # gather up a symbol/keyword
204 elif c in syminitletters:
204 elif c in syminitletters:
205 s = pos
205 s = pos
206 pos += 1
206 pos += 1
207 while pos < l: # find end of symbol
207 while pos < l: # find end of symbol
208 d = program[pos]
208 d = program[pos]
209 if d not in symletters:
209 if d not in symletters:
210 break
210 break
211 if d == '.' and program[pos - 1] == '.': # special case for ..
211 if d == '.' and program[pos - 1] == '.': # special case for ..
212 pos -= 1
212 pos -= 1
213 break
213 break
214 pos += 1
214 pos += 1
215 sym = program[s:pos]
215 sym = program[s:pos]
216 if sym in keywords: # operator keywords
216 if sym in keywords: # operator keywords
217 yield (sym, None, s)
217 yield (sym, None, s)
218 elif '-' in sym:
218 elif '-' in sym:
219 # some jerk gave us foo-bar-baz, try to check if it's a symbol
219 # some jerk gave us foo-bar-baz, try to check if it's a symbol
220 if lookup and lookup(sym):
220 if lookup and lookup(sym):
221 # looks like a real symbol
221 # looks like a real symbol
222 yield ('symbol', sym, s)
222 yield ('symbol', sym, s)
223 else:
223 else:
224 # looks like an expression
224 # looks like an expression
225 parts = sym.split('-')
225 parts = sym.split('-')
226 for p in parts[:-1]:
226 for p in parts[:-1]:
227 if p: # possible consecutive -
227 if p: # possible consecutive -
228 yield ('symbol', p, s)
228 yield ('symbol', p, s)
229 s += len(p)
229 s += len(p)
230 yield ('-', None, pos)
230 yield ('-', None, pos)
231 s += 1
231 s += 1
232 if parts[-1]: # possible trailing -
232 if parts[-1]: # possible trailing -
233 yield ('symbol', parts[-1], s)
233 yield ('symbol', parts[-1], s)
234 else:
234 else:
235 yield ('symbol', sym, s)
235 yield ('symbol', sym, s)
236 pos -= 1
236 pos -= 1
237 else:
237 else:
238 raise error.ParseError(_("syntax error"), pos)
238 raise error.ParseError(_("syntax error"), pos)
239 pos += 1
239 pos += 1
240 yield ('end', None, pos)
240 yield ('end', None, pos)
241
241
242 def parseerrordetail(inst):
242 def parseerrordetail(inst):
243 """Compose error message from specified ParseError object
243 """Compose error message from specified ParseError object
244 """
244 """
245 if len(inst.args) > 1:
245 if len(inst.args) > 1:
246 return _('at %s: %s') % (inst.args[1], inst.args[0])
246 return _('at %s: %s') % (inst.args[1], inst.args[0])
247 else:
247 else:
248 return inst.args[0]
248 return inst.args[0]
249
249
250 # helpers
250 # helpers
251
251
252 def getstring(x, err):
252 def getstring(x, err):
253 if x and (x[0] == 'string' or x[0] == 'symbol'):
253 if x and (x[0] == 'string' or x[0] == 'symbol'):
254 return x[1]
254 return x[1]
255 raise error.ParseError(err)
255 raise error.ParseError(err)
256
256
257 def getlist(x):
257 def getlist(x):
258 if not x:
258 if not x:
259 return []
259 return []
260 if x[0] == 'list':
260 if x[0] == 'list':
261 return getlist(x[1]) + [x[2]]
261 return getlist(x[1]) + [x[2]]
262 return [x]
262 return [x]
263
263
264 def getargs(x, min, max, err):
264 def getargs(x, min, max, err):
265 l = getlist(x)
265 l = getlist(x)
266 if len(l) < min or (max >= 0 and len(l) > max):
266 if len(l) < min or (max >= 0 and len(l) > max):
267 raise error.ParseError(err)
267 raise error.ParseError(err)
268 return l
268 return l
269
269
270 def isvalidsymbol(tree):
270 def isvalidsymbol(tree):
271 """Examine whether specified ``tree`` is valid ``symbol`` or not
271 """Examine whether specified ``tree`` is valid ``symbol`` or not
272 """
272 """
273 return tree[0] == 'symbol' and len(tree) > 1
273 return tree[0] == 'symbol' and len(tree) > 1
274
274
275 def getsymbol(tree):
275 def getsymbol(tree):
276 """Get symbol name from valid ``symbol`` in ``tree``
276 """Get symbol name from valid ``symbol`` in ``tree``
277
277
278 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
278 This assumes that ``tree`` is already examined by ``isvalidsymbol``.
279 """
279 """
280 return tree[1]
280 return tree[1]
281
281
282 def isvalidfunc(tree):
282 def isvalidfunc(tree):
283 """Examine whether specified ``tree`` is valid ``func`` or not
283 """Examine whether specified ``tree`` is valid ``func`` or not
284 """
284 """
285 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
285 return tree[0] == 'func' and len(tree) > 1 and isvalidsymbol(tree[1])
286
286
287 def getfuncname(tree):
287 def getfuncname(tree):
288 """Get function name from valid ``func`` in ``tree``
288 """Get function name from valid ``func`` in ``tree``
289
289
290 This assumes that ``tree`` is already examined by ``isvalidfunc``.
290 This assumes that ``tree`` is already examined by ``isvalidfunc``.
291 """
291 """
292 return getsymbol(tree[1])
292 return getsymbol(tree[1])
293
293
294 def getfuncargs(tree):
294 def getfuncargs(tree):
295 """Get list of function arguments from valid ``func`` in ``tree``
295 """Get list of function arguments 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 if len(tree) > 2:
299 if len(tree) > 2:
300 return getlist(tree[2])
300 return getlist(tree[2])
301 else:
301 else:
302 return []
302 return []
303
303
304 def getset(repo, subset, x):
304 def getset(repo, subset, x):
305 if not x:
305 if not x:
306 raise error.ParseError(_("missing argument"))
306 raise error.ParseError(_("missing argument"))
307 s = methods[x[0]](repo, subset, *x[1:])
307 s = methods[x[0]](repo, subset, *x[1:])
308 if util.safehasattr(s, 'isascending'):
308 if util.safehasattr(s, 'isascending'):
309 return s
309 return s
310 return baseset(s)
310 return baseset(s)
311
311
312 def _getrevsource(repo, r):
312 def _getrevsource(repo, r):
313 extra = repo[r].extra()
313 extra = repo[r].extra()
314 for label in ('source', 'transplant_source', 'rebase_source'):
314 for label in ('source', 'transplant_source', 'rebase_source'):
315 if label in extra:
315 if label in extra:
316 try:
316 try:
317 return repo[extra[label]].rev()
317 return repo[extra[label]].rev()
318 except error.RepoLookupError:
318 except error.RepoLookupError:
319 pass
319 pass
320 return None
320 return None
321
321
322 # operator methods
322 # operator methods
323
323
324 def stringset(repo, subset, x):
324 def stringset(repo, subset, x):
325 x = repo[x].rev()
325 x = repo[x].rev()
326 if x == -1 and len(subset) == len(repo):
326 if x == -1 and len(subset) == len(repo):
327 return baseset([-1])
327 return baseset([-1])
328 if x in subset:
328 if x in subset:
329 return baseset([x])
329 return baseset([x])
330 return baseset()
330 return baseset()
331
331
332 def symbolset(repo, subset, x):
332 def symbolset(repo, subset, x):
333 if x in symbols:
333 if x in symbols:
334 raise error.ParseError(_("can't use %s here") % x)
334 raise error.ParseError(_("can't use %s here") % x)
335 return stringset(repo, subset, x)
335 return stringset(repo, subset, x)
336
336
337 def rangeset(repo, subset, x, y):
337 def rangeset(repo, subset, x, y):
338 m = getset(repo, fullreposet(repo), x)
338 m = getset(repo, fullreposet(repo), x)
339 n = getset(repo, fullreposet(repo), y)
339 n = getset(repo, fullreposet(repo), y)
340
340
341 if not m or not n:
341 if not m or not n:
342 return baseset()
342 return baseset()
343 m, n = m.first(), n.last()
343 m, n = m.first(), n.last()
344
344
345 if m < n:
345 if m < n:
346 r = spanset(repo, m, n + 1)
346 r = spanset(repo, m, n + 1)
347 else:
347 else:
348 r = spanset(repo, m, n - 1)
348 r = spanset(repo, m, n - 1)
349 return r & subset
349 return r & subset
350
350
351 def dagrange(repo, subset, x, y):
351 def dagrange(repo, subset, x, y):
352 r = spanset(repo)
352 r = spanset(repo)
353 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
353 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
354 return xs & subset
354 return xs & subset
355
355
356 def andset(repo, subset, x, y):
356 def andset(repo, subset, x, y):
357 return getset(repo, getset(repo, subset, x), y)
357 return getset(repo, getset(repo, subset, x), y)
358
358
359 def orset(repo, subset, x, y):
359 def orset(repo, subset, x, y):
360 xl = getset(repo, subset, x)
360 xl = getset(repo, subset, x)
361 yl = getset(repo, subset - xl, y)
361 yl = getset(repo, subset - xl, y)
362 return xl + yl
362 return xl + yl
363
363
364 def notset(repo, subset, x):
364 def notset(repo, subset, x):
365 return subset - getset(repo, subset, x)
365 return subset - getset(repo, subset, x)
366
366
367 def listset(repo, subset, a, b):
367 def listset(repo, subset, a, b):
368 raise error.ParseError(_("can't use a list in this context"))
368 raise error.ParseError(_("can't use a list in this context"))
369
369
370 def func(repo, subset, a, b):
370 def func(repo, subset, a, b):
371 if a[0] == 'symbol' and a[1] in symbols:
371 if a[0] == 'symbol' and a[1] in symbols:
372 return symbols[a[1]](repo, subset, b)
372 return symbols[a[1]](repo, subset, b)
373 raise error.ParseError(_("not a function: %s") % a[1])
373 raise error.ParseError(_("not a function: %s") % a[1])
374
374
375 # functions
375 # functions
376
376
377 def adds(repo, subset, x):
377 def adds(repo, subset, x):
378 """``adds(pattern)``
378 """``adds(pattern)``
379 Changesets that add a file matching pattern.
379 Changesets that add a file matching pattern.
380
380
381 The pattern without explicit kind like ``glob:`` is expected to be
381 The pattern without explicit kind like ``glob:`` is expected to be
382 relative to the current directory and match against a file or a
382 relative to the current directory and match against a file or a
383 directory.
383 directory.
384 """
384 """
385 # i18n: "adds" is a keyword
385 # i18n: "adds" is a keyword
386 pat = getstring(x, _("adds requires a pattern"))
386 pat = getstring(x, _("adds requires a pattern"))
387 return checkstatus(repo, subset, pat, 1)
387 return checkstatus(repo, subset, pat, 1)
388
388
389 def ancestor(repo, subset, x):
389 def ancestor(repo, subset, x):
390 """``ancestor(*changeset)``
390 """``ancestor(*changeset)``
391 A greatest common ancestor of the changesets.
391 A greatest common ancestor of the changesets.
392
392
393 Accepts 0 or more changesets.
393 Accepts 0 or more changesets.
394 Will return empty list when passed no args.
394 Will return empty list when passed no args.
395 Greatest common ancestor of a single changeset is that changeset.
395 Greatest common ancestor of a single changeset is that changeset.
396 """
396 """
397 # i18n: "ancestor" is a keyword
397 # i18n: "ancestor" is a keyword
398 l = getlist(x)
398 l = getlist(x)
399 rl = spanset(repo)
399 rl = spanset(repo)
400 anc = None
400 anc = None
401
401
402 # (getset(repo, rl, i) for i in l) generates a list of lists
402 # (getset(repo, rl, i) for i in l) generates a list of lists
403 for revs in (getset(repo, rl, i) for i in l):
403 for revs in (getset(repo, rl, i) for i in l):
404 for r in revs:
404 for r in revs:
405 if anc is None:
405 if anc is None:
406 anc = repo[r]
406 anc = repo[r]
407 else:
407 else:
408 anc = anc.ancestor(repo[r])
408 anc = anc.ancestor(repo[r])
409
409
410 if anc is not None and anc.rev() in subset:
410 if anc is not None and anc.rev() in subset:
411 return baseset([anc.rev()])
411 return baseset([anc.rev()])
412 return baseset()
412 return baseset()
413
413
414 def _ancestors(repo, subset, x, followfirst=False):
414 def _ancestors(repo, subset, x, followfirst=False):
415 heads = getset(repo, spanset(repo), x)
415 heads = getset(repo, spanset(repo), x)
416 if not heads:
416 if not heads:
417 return baseset()
417 return baseset()
418 s = _revancestors(repo, heads, followfirst)
418 s = _revancestors(repo, heads, followfirst)
419 return subset & s
419 return subset & s
420
420
421 def ancestors(repo, subset, x):
421 def ancestors(repo, subset, x):
422 """``ancestors(set)``
422 """``ancestors(set)``
423 Changesets that are ancestors of a changeset in set.
423 Changesets that are ancestors of a changeset in set.
424 """
424 """
425 return _ancestors(repo, subset, x)
425 return _ancestors(repo, subset, x)
426
426
427 def _firstancestors(repo, subset, x):
427 def _firstancestors(repo, subset, x):
428 # ``_firstancestors(set)``
428 # ``_firstancestors(set)``
429 # Like ``ancestors(set)`` but follows only the first parents.
429 # Like ``ancestors(set)`` but follows only the first parents.
430 return _ancestors(repo, subset, x, followfirst=True)
430 return _ancestors(repo, subset, x, followfirst=True)
431
431
432 def ancestorspec(repo, subset, x, n):
432 def ancestorspec(repo, subset, x, n):
433 """``set~n``
433 """``set~n``
434 Changesets that are the Nth ancestor (first parents only) of a changeset
434 Changesets that are the Nth ancestor (first parents only) of a changeset
435 in set.
435 in set.
436 """
436 """
437 try:
437 try:
438 n = int(n[1])
438 n = int(n[1])
439 except (TypeError, ValueError):
439 except (TypeError, ValueError):
440 raise error.ParseError(_("~ expects a number"))
440 raise error.ParseError(_("~ expects a number"))
441 ps = set()
441 ps = set()
442 cl = repo.changelog
442 cl = repo.changelog
443 for r in getset(repo, fullreposet(repo), x):
443 for r in getset(repo, fullreposet(repo), x):
444 for i in range(n):
444 for i in range(n):
445 r = cl.parentrevs(r)[0]
445 r = cl.parentrevs(r)[0]
446 ps.add(r)
446 ps.add(r)
447 return subset & ps
447 return subset & ps
448
448
449 def author(repo, subset, x):
449 def author(repo, subset, x):
450 """``author(string)``
450 """``author(string)``
451 Alias for ``user(string)``.
451 Alias for ``user(string)``.
452 """
452 """
453 # i18n: "author" is a keyword
453 # i18n: "author" is a keyword
454 n = encoding.lower(getstring(x, _("author requires a string")))
454 n = encoding.lower(getstring(x, _("author requires a string")))
455 kind, pattern, matcher = _substringmatcher(n)
455 kind, pattern, matcher = _substringmatcher(n)
456 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
456 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
457
457
458 def bisect(repo, subset, x):
458 def bisect(repo, subset, x):
459 """``bisect(string)``
459 """``bisect(string)``
460 Changesets marked in the specified bisect status:
460 Changesets marked in the specified bisect status:
461
461
462 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
462 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
463 - ``goods``, ``bads`` : csets topologically good/bad
463 - ``goods``, ``bads`` : csets topologically good/bad
464 - ``range`` : csets taking part in the bisection
464 - ``range`` : csets taking part in the bisection
465 - ``pruned`` : csets that are goods, bads or skipped
465 - ``pruned`` : csets that are goods, bads or skipped
466 - ``untested`` : csets whose fate is yet unknown
466 - ``untested`` : csets whose fate is yet unknown
467 - ``ignored`` : csets ignored due to DAG topology
467 - ``ignored`` : csets ignored due to DAG topology
468 - ``current`` : the cset currently being bisected
468 - ``current`` : the cset currently being bisected
469 """
469 """
470 # i18n: "bisect" is a keyword
470 # i18n: "bisect" is a keyword
471 status = getstring(x, _("bisect requires a string")).lower()
471 status = getstring(x, _("bisect requires a string")).lower()
472 state = set(hbisect.get(repo, status))
472 state = set(hbisect.get(repo, status))
473 return subset & state
473 return subset & state
474
474
475 # Backward-compatibility
475 # Backward-compatibility
476 # - no help entry so that we do not advertise it any more
476 # - no help entry so that we do not advertise it any more
477 def bisected(repo, subset, x):
477 def bisected(repo, subset, x):
478 return bisect(repo, subset, x)
478 return bisect(repo, subset, x)
479
479
480 def bookmark(repo, subset, x):
480 def bookmark(repo, subset, x):
481 """``bookmark([name])``
481 """``bookmark([name])``
482 The named bookmark or all bookmarks.
482 The named bookmark or all bookmarks.
483
483
484 If `name` starts with `re:`, the remainder of the name is treated as
484 If `name` starts with `re:`, the remainder of the name is treated as
485 a regular expression. To match a bookmark that actually starts with `re:`,
485 a regular expression. To match a bookmark that actually starts with `re:`,
486 use the prefix `literal:`.
486 use the prefix `literal:`.
487 """
487 """
488 # i18n: "bookmark" is a keyword
488 # i18n: "bookmark" is a keyword
489 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
489 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
490 if args:
490 if args:
491 bm = getstring(args[0],
491 bm = getstring(args[0],
492 # i18n: "bookmark" is a keyword
492 # i18n: "bookmark" is a keyword
493 _('the argument to bookmark must be a string'))
493 _('the argument to bookmark must be a string'))
494 kind, pattern, matcher = _stringmatcher(bm)
494 kind, pattern, matcher = _stringmatcher(bm)
495 bms = set()
495 bms = set()
496 if kind == 'literal':
496 if kind == 'literal':
497 bmrev = repo._bookmarks.get(pattern, None)
497 bmrev = repo._bookmarks.get(pattern, None)
498 if not bmrev:
498 if not bmrev:
499 raise util.Abort(_("bookmark '%s' does not exist") % bm)
499 raise util.Abort(_("bookmark '%s' does not exist") % bm)
500 bms.add(repo[bmrev].rev())
500 bms.add(repo[bmrev].rev())
501 else:
501 else:
502 matchrevs = set()
502 matchrevs = set()
503 for name, bmrev in repo._bookmarks.iteritems():
503 for name, bmrev in repo._bookmarks.iteritems():
504 if matcher(name):
504 if matcher(name):
505 matchrevs.add(bmrev)
505 matchrevs.add(bmrev)
506 if not matchrevs:
506 if not matchrevs:
507 raise util.Abort(_("no bookmarks exist that match '%s'")
507 raise util.Abort(_("no bookmarks exist that match '%s'")
508 % pattern)
508 % pattern)
509 for bmrev in matchrevs:
509 for bmrev in matchrevs:
510 bms.add(repo[bmrev].rev())
510 bms.add(repo[bmrev].rev())
511 else:
511 else:
512 bms = set([repo[r].rev()
512 bms = set([repo[r].rev()
513 for r in repo._bookmarks.values()])
513 for r in repo._bookmarks.values()])
514 bms -= set([node.nullrev])
514 bms -= set([node.nullrev])
515 return subset & bms
515 return subset & bms
516
516
517 def branch(repo, subset, x):
517 def branch(repo, subset, x):
518 """``branch(string or set)``
518 """``branch(string or set)``
519 All changesets belonging to the given branch or the branches of the given
519 All changesets belonging to the given branch or the branches of the given
520 changesets.
520 changesets.
521
521
522 If `string` starts with `re:`, the remainder of the name is treated as
522 If `string` starts with `re:`, the remainder of the name is treated as
523 a regular expression. To match a branch that actually starts with `re:`,
523 a regular expression. To match a branch that actually starts with `re:`,
524 use the prefix `literal:`.
524 use the prefix `literal:`.
525 """
525 """
526 import branchmap
526 import branchmap
527 urepo = repo.unfiltered()
527 urepo = repo.unfiltered()
528 ucl = urepo.changelog
528 ucl = urepo.changelog
529 getbi = branchmap.revbranchcache(urepo).branchinfo
529 getbi = branchmap.revbranchcache(urepo).branchinfo
530
530
531 try:
531 try:
532 b = getstring(x, '')
532 b = getstring(x, '')
533 except error.ParseError:
533 except error.ParseError:
534 # not a string, but another revspec, e.g. tip()
534 # not a string, but another revspec, e.g. tip()
535 pass
535 pass
536 else:
536 else:
537 kind, pattern, matcher = _stringmatcher(b)
537 kind, pattern, matcher = _stringmatcher(b)
538 if kind == 'literal':
538 if kind == 'literal':
539 # note: falls through to the revspec case if no branch with
539 # note: falls through to the revspec case if no branch with
540 # this name exists
540 # this name exists
541 if pattern in repo.branchmap():
541 if pattern in repo.branchmap():
542 return subset.filter(lambda r: matcher(getbi(ucl, r)[0]))
542 return subset.filter(lambda r: matcher(getbi(ucl, r)[0]))
543 else:
543 else:
544 return subset.filter(lambda r: matcher(getbi(ucl, r)[0]))
544 return subset.filter(lambda r: matcher(getbi(ucl, r)[0]))
545
545
546 s = getset(repo, spanset(repo), x)
546 s = getset(repo, spanset(repo), x)
547 b = set()
547 b = set()
548 for r in s:
548 for r in s:
549 b.add(getbi(ucl, r)[0])
549 b.add(getbi(ucl, r)[0])
550 c = s.__contains__
550 c = s.__contains__
551 return subset.filter(lambda r: c(r) or getbi(ucl, r)[0] in b)
551 return subset.filter(lambda r: c(r) or getbi(ucl, r)[0] in b)
552
552
553 def bumped(repo, subset, x):
553 def bumped(repo, subset, x):
554 """``bumped()``
554 """``bumped()``
555 Mutable changesets marked as successors of public changesets.
555 Mutable changesets marked as successors of public changesets.
556
556
557 Only non-public and non-obsolete changesets can be `bumped`.
557 Only non-public and non-obsolete changesets can be `bumped`.
558 """
558 """
559 # i18n: "bumped" is a keyword
559 # i18n: "bumped" is a keyword
560 getargs(x, 0, 0, _("bumped takes no arguments"))
560 getargs(x, 0, 0, _("bumped takes no arguments"))
561 bumped = obsmod.getrevs(repo, 'bumped')
561 bumped = obsmod.getrevs(repo, 'bumped')
562 return subset & bumped
562 return subset & bumped
563
563
564 def bundle(repo, subset, x):
564 def bundle(repo, subset, x):
565 """``bundle()``
565 """``bundle()``
566 Changesets in the bundle.
566 Changesets in the bundle.
567
567
568 Bundle must be specified by the -R option."""
568 Bundle must be specified by the -R option."""
569
569
570 try:
570 try:
571 bundlerevs = repo.changelog.bundlerevs
571 bundlerevs = repo.changelog.bundlerevs
572 except AttributeError:
572 except AttributeError:
573 raise util.Abort(_("no bundle provided - specify with -R"))
573 raise util.Abort(_("no bundle provided - specify with -R"))
574 return subset & bundlerevs
574 return subset & bundlerevs
575
575
576 def checkstatus(repo, subset, pat, field):
576 def checkstatus(repo, subset, pat, field):
577 hasset = matchmod.patkind(pat) == 'set'
577 hasset = matchmod.patkind(pat) == 'set'
578
578
579 mcache = [None]
579 mcache = [None]
580 def matches(x):
580 def matches(x):
581 c = repo[x]
581 c = repo[x]
582 if not mcache[0] or hasset:
582 if not mcache[0] or hasset:
583 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
583 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
584 m = mcache[0]
584 m = mcache[0]
585 fname = None
585 fname = None
586 if not m.anypats() and len(m.files()) == 1:
586 if not m.anypats() and len(m.files()) == 1:
587 fname = m.files()[0]
587 fname = m.files()[0]
588 if fname is not None:
588 if fname is not None:
589 if fname not in c.files():
589 if fname not in c.files():
590 return False
590 return False
591 else:
591 else:
592 for f in c.files():
592 for f in c.files():
593 if m(f):
593 if m(f):
594 break
594 break
595 else:
595 else:
596 return False
596 return False
597 files = repo.status(c.p1().node(), c.node())[field]
597 files = repo.status(c.p1().node(), c.node())[field]
598 if fname is not None:
598 if fname is not None:
599 if fname in files:
599 if fname in files:
600 return True
600 return True
601 else:
601 else:
602 for f in files:
602 for f in files:
603 if m(f):
603 if m(f):
604 return True
604 return True
605
605
606 return subset.filter(matches)
606 return subset.filter(matches)
607
607
608 def _children(repo, narrow, parentset):
608 def _children(repo, narrow, parentset):
609 cs = set()
609 cs = set()
610 if not parentset:
610 if not parentset:
611 return baseset(cs)
611 return baseset(cs)
612 pr = repo.changelog.parentrevs
612 pr = repo.changelog.parentrevs
613 minrev = min(parentset)
613 minrev = min(parentset)
614 for r in narrow:
614 for r in narrow:
615 if r <= minrev:
615 if r <= minrev:
616 continue
616 continue
617 for p in pr(r):
617 for p in pr(r):
618 if p in parentset:
618 if p in parentset:
619 cs.add(r)
619 cs.add(r)
620 return baseset(cs)
620 return baseset(cs)
621
621
622 def children(repo, subset, x):
622 def children(repo, subset, x):
623 """``children(set)``
623 """``children(set)``
624 Child changesets of changesets in set.
624 Child changesets of changesets in set.
625 """
625 """
626 s = getset(repo, fullreposet(repo), x)
626 s = getset(repo, fullreposet(repo), x)
627 cs = _children(repo, subset, s)
627 cs = _children(repo, subset, s)
628 return subset & cs
628 return subset & cs
629
629
630 def closed(repo, subset, x):
630 def closed(repo, subset, x):
631 """``closed()``
631 """``closed()``
632 Changeset is closed.
632 Changeset is closed.
633 """
633 """
634 # i18n: "closed" is a keyword
634 # i18n: "closed" is a keyword
635 getargs(x, 0, 0, _("closed takes no arguments"))
635 getargs(x, 0, 0, _("closed takes no arguments"))
636 return subset.filter(lambda r: repo[r].closesbranch())
636 return subset.filter(lambda r: repo[r].closesbranch())
637
637
638 def contains(repo, subset, x):
638 def contains(repo, subset, x):
639 """``contains(pattern)``
639 """``contains(pattern)``
640 The revision's manifest contains a file matching pattern (but might not
640 The revision's manifest contains a file matching pattern (but might not
641 modify it). See :hg:`help patterns` for information about file patterns.
641 modify it). See :hg:`help patterns` for information about file patterns.
642
642
643 The pattern without explicit kind like ``glob:`` is expected to be
643 The pattern without explicit kind like ``glob:`` is expected to be
644 relative to the current directory and match against a file exactly
644 relative to the current directory and match against a file exactly
645 for efficiency.
645 for efficiency.
646 """
646 """
647 # i18n: "contains" is a keyword
647 # i18n: "contains" is a keyword
648 pat = getstring(x, _("contains requires a pattern"))
648 pat = getstring(x, _("contains requires a pattern"))
649
649
650 def matches(x):
650 def matches(x):
651 if not matchmod.patkind(pat):
651 if not matchmod.patkind(pat):
652 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
652 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
653 if pats in repo[x]:
653 if pats in repo[x]:
654 return True
654 return True
655 else:
655 else:
656 c = repo[x]
656 c = repo[x]
657 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
657 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
658 for f in c.manifest():
658 for f in c.manifest():
659 if m(f):
659 if m(f):
660 return True
660 return True
661 return False
661 return False
662
662
663 return subset.filter(matches)
663 return subset.filter(matches)
664
664
665 def converted(repo, subset, x):
665 def converted(repo, subset, x):
666 """``converted([id])``
666 """``converted([id])``
667 Changesets converted from the given identifier in the old repository if
667 Changesets converted from the given identifier in the old repository if
668 present, or all converted changesets if no identifier is specified.
668 present, or all converted changesets if no identifier is specified.
669 """
669 """
670
670
671 # There is exactly no chance of resolving the revision, so do a simple
671 # There is exactly no chance of resolving the revision, so do a simple
672 # string compare and hope for the best
672 # string compare and hope for the best
673
673
674 rev = None
674 rev = None
675 # i18n: "converted" is a keyword
675 # i18n: "converted" is a keyword
676 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
676 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
677 if l:
677 if l:
678 # i18n: "converted" is a keyword
678 # i18n: "converted" is a keyword
679 rev = getstring(l[0], _('converted requires a revision'))
679 rev = getstring(l[0], _('converted requires a revision'))
680
680
681 def _matchvalue(r):
681 def _matchvalue(r):
682 source = repo[r].extra().get('convert_revision', None)
682 source = repo[r].extra().get('convert_revision', None)
683 return source is not None and (rev is None or source.startswith(rev))
683 return source is not None and (rev is None or source.startswith(rev))
684
684
685 return subset.filter(lambda r: _matchvalue(r))
685 return subset.filter(lambda r: _matchvalue(r))
686
686
687 def date(repo, subset, x):
687 def date(repo, subset, x):
688 """``date(interval)``
688 """``date(interval)``
689 Changesets within the interval, see :hg:`help dates`.
689 Changesets within the interval, see :hg:`help dates`.
690 """
690 """
691 # i18n: "date" is a keyword
691 # i18n: "date" is a keyword
692 ds = getstring(x, _("date requires a string"))
692 ds = getstring(x, _("date requires a string"))
693 dm = util.matchdate(ds)
693 dm = util.matchdate(ds)
694 return subset.filter(lambda x: dm(repo[x].date()[0]))
694 return subset.filter(lambda x: dm(repo[x].date()[0]))
695
695
696 def desc(repo, subset, x):
696 def desc(repo, subset, x):
697 """``desc(string)``
697 """``desc(string)``
698 Search commit message for string. The match is case-insensitive.
698 Search commit message for string. The match is case-insensitive.
699 """
699 """
700 # i18n: "desc" is a keyword
700 # i18n: "desc" is a keyword
701 ds = encoding.lower(getstring(x, _("desc requires a string")))
701 ds = encoding.lower(getstring(x, _("desc requires a string")))
702
702
703 def matches(x):
703 def matches(x):
704 c = repo[x]
704 c = repo[x]
705 return ds in encoding.lower(c.description())
705 return ds in encoding.lower(c.description())
706
706
707 return subset.filter(matches)
707 return subset.filter(matches)
708
708
709 def _descendants(repo, subset, x, followfirst=False):
709 def _descendants(repo, subset, x, followfirst=False):
710 roots = getset(repo, spanset(repo), x)
710 roots = getset(repo, spanset(repo), x)
711 if not roots:
711 if not roots:
712 return baseset()
712 return baseset()
713 s = _revdescendants(repo, roots, followfirst)
713 s = _revdescendants(repo, roots, followfirst)
714
714
715 # Both sets need to be ascending in order to lazily return the union
715 # Both sets need to be ascending in order to lazily return the union
716 # in the correct order.
716 # in the correct order.
717 base = subset & roots
717 base = subset & roots
718 desc = subset & s
718 desc = subset & s
719 result = base + desc
719 result = base + desc
720 if subset.isascending():
720 if subset.isascending():
721 result.sort()
721 result.sort()
722 elif subset.isdescending():
722 elif subset.isdescending():
723 result.sort(reverse=True)
723 result.sort(reverse=True)
724 else:
724 else:
725 result = subset & result
725 result = subset & result
726 return result
726 return result
727
727
728 def descendants(repo, subset, x):
728 def descendants(repo, subset, x):
729 """``descendants(set)``
729 """``descendants(set)``
730 Changesets which are descendants of changesets in set.
730 Changesets which are descendants of changesets in set.
731 """
731 """
732 return _descendants(repo, subset, x)
732 return _descendants(repo, subset, x)
733
733
734 def _firstdescendants(repo, subset, x):
734 def _firstdescendants(repo, subset, x):
735 # ``_firstdescendants(set)``
735 # ``_firstdescendants(set)``
736 # Like ``descendants(set)`` but follows only the first parents.
736 # Like ``descendants(set)`` but follows only the first parents.
737 return _descendants(repo, subset, x, followfirst=True)
737 return _descendants(repo, subset, x, followfirst=True)
738
738
739 def destination(repo, subset, x):
739 def destination(repo, subset, x):
740 """``destination([set])``
740 """``destination([set])``
741 Changesets that were created by a graft, transplant or rebase operation,
741 Changesets that were created by a graft, transplant or rebase operation,
742 with the given revisions specified as the source. Omitting the optional set
742 with the given revisions specified as the source. Omitting the optional set
743 is the same as passing all().
743 is the same as passing all().
744 """
744 """
745 if x is not None:
745 if x is not None:
746 sources = getset(repo, spanset(repo), x)
746 sources = getset(repo, spanset(repo), x)
747 else:
747 else:
748 sources = getall(repo, spanset(repo), x)
748 sources = getall(repo, spanset(repo), x)
749
749
750 dests = set()
750 dests = set()
751
751
752 # subset contains all of the possible destinations that can be returned, so
752 # subset contains all of the possible destinations that can be returned, so
753 # iterate over them and see if their source(s) were provided in the arg set.
753 # iterate over them and see if their source(s) were provided in the arg set.
754 # Even if the immediate src of r is not in the arg set, src's source (or
754 # Even if the immediate src of r is not in the arg set, src's source (or
755 # further back) may be. Scanning back further than the immediate src allows
755 # further back) may be. Scanning back further than the immediate src allows
756 # transitive transplants and rebases to yield the same results as transitive
756 # transitive transplants and rebases to yield the same results as transitive
757 # grafts.
757 # grafts.
758 for r in subset:
758 for r in subset:
759 src = _getrevsource(repo, r)
759 src = _getrevsource(repo, r)
760 lineage = None
760 lineage = None
761
761
762 while src is not None:
762 while src is not None:
763 if lineage is None:
763 if lineage is None:
764 lineage = list()
764 lineage = list()
765
765
766 lineage.append(r)
766 lineage.append(r)
767
767
768 # The visited lineage is a match if the current source is in the arg
768 # The visited lineage is a match if the current source is in the arg
769 # set. Since every candidate dest is visited by way of iterating
769 # set. Since every candidate dest is visited by way of iterating
770 # subset, any dests further back in the lineage will be tested by a
770 # subset, any dests further back in the lineage will be tested by a
771 # different iteration over subset. Likewise, if the src was already
771 # different iteration over subset. Likewise, if the src was already
772 # selected, the current lineage can be selected without going back
772 # selected, the current lineage can be selected without going back
773 # further.
773 # further.
774 if src in sources or src in dests:
774 if src in sources or src in dests:
775 dests.update(lineage)
775 dests.update(lineage)
776 break
776 break
777
777
778 r = src
778 r = src
779 src = _getrevsource(repo, r)
779 src = _getrevsource(repo, r)
780
780
781 return subset.filter(dests.__contains__)
781 return subset.filter(dests.__contains__)
782
782
783 def divergent(repo, subset, x):
783 def divergent(repo, subset, x):
784 """``divergent()``
784 """``divergent()``
785 Final successors of changesets with an alternative set of final successors.
785 Final successors of changesets with an alternative set of final successors.
786 """
786 """
787 # i18n: "divergent" is a keyword
787 # i18n: "divergent" is a keyword
788 getargs(x, 0, 0, _("divergent takes no arguments"))
788 getargs(x, 0, 0, _("divergent takes no arguments"))
789 divergent = obsmod.getrevs(repo, 'divergent')
789 divergent = obsmod.getrevs(repo, 'divergent')
790 return subset & divergent
790 return subset & divergent
791
791
792 def draft(repo, subset, x):
792 def draft(repo, subset, x):
793 """``draft()``
793 """``draft()``
794 Changeset in draft phase."""
794 Changeset in draft phase."""
795 # i18n: "draft" is a keyword
795 # i18n: "draft" is a keyword
796 getargs(x, 0, 0, _("draft takes no arguments"))
796 getargs(x, 0, 0, _("draft takes no arguments"))
797 phase = repo._phasecache.phase
797 phase = repo._phasecache.phase
798 target = phases.draft
798 target = phases.draft
799 condition = lambda r: phase(repo, r) == target
799 condition = lambda r: phase(repo, r) == target
800 return subset.filter(condition, cache=False)
800 return subset.filter(condition, cache=False)
801
801
802 def extinct(repo, subset, x):
802 def extinct(repo, subset, x):
803 """``extinct()``
803 """``extinct()``
804 Obsolete changesets with obsolete descendants only.
804 Obsolete changesets with obsolete descendants only.
805 """
805 """
806 # i18n: "extinct" is a keyword
806 # i18n: "extinct" is a keyword
807 getargs(x, 0, 0, _("extinct takes no arguments"))
807 getargs(x, 0, 0, _("extinct takes no arguments"))
808 extincts = obsmod.getrevs(repo, 'extinct')
808 extincts = obsmod.getrevs(repo, 'extinct')
809 return subset & extincts
809 return subset & extincts
810
810
811 def extra(repo, subset, x):
811 def extra(repo, subset, x):
812 """``extra(label, [value])``
812 """``extra(label, [value])``
813 Changesets with the given label in the extra metadata, with the given
813 Changesets with the given label in the extra metadata, with the given
814 optional value.
814 optional value.
815
815
816 If `value` starts with `re:`, the remainder of the value is treated as
816 If `value` starts with `re:`, the remainder of the value is treated as
817 a regular expression. To match a value that actually starts with `re:`,
817 a regular expression. To match a value that actually starts with `re:`,
818 use the prefix `literal:`.
818 use the prefix `literal:`.
819 """
819 """
820
820
821 # i18n: "extra" is a keyword
821 # i18n: "extra" is a keyword
822 l = getargs(x, 1, 2, _('extra takes at least 1 and at most 2 arguments'))
822 l = getargs(x, 1, 2, _('extra takes at least 1 and at most 2 arguments'))
823 # i18n: "extra" is a keyword
823 # i18n: "extra" is a keyword
824 label = getstring(l[0], _('first argument to extra must be a string'))
824 label = getstring(l[0], _('first argument to extra must be a string'))
825 value = None
825 value = None
826
826
827 if len(l) > 1:
827 if len(l) > 1:
828 # i18n: "extra" is a keyword
828 # i18n: "extra" is a keyword
829 value = getstring(l[1], _('second argument to extra must be a string'))
829 value = getstring(l[1], _('second argument to extra must be a string'))
830 kind, value, matcher = _stringmatcher(value)
830 kind, value, matcher = _stringmatcher(value)
831
831
832 def _matchvalue(r):
832 def _matchvalue(r):
833 extra = repo[r].extra()
833 extra = repo[r].extra()
834 return label in extra and (value is None or matcher(extra[label]))
834 return label in extra and (value is None or matcher(extra[label]))
835
835
836 return subset.filter(lambda r: _matchvalue(r))
836 return subset.filter(lambda r: _matchvalue(r))
837
837
838 def filelog(repo, subset, x):
838 def filelog(repo, subset, x):
839 """``filelog(pattern)``
839 """``filelog(pattern)``
840 Changesets connected to the specified filelog.
840 Changesets connected to the specified filelog.
841
841
842 For performance reasons, visits only revisions mentioned in the file-level
842 For performance reasons, visits only revisions mentioned in the file-level
843 filelog, rather than filtering through all changesets (much faster, but
843 filelog, rather than filtering through all changesets (much faster, but
844 doesn't include deletes or duplicate changes). For a slower, more accurate
844 doesn't include deletes or duplicate changes). For a slower, more accurate
845 result, use ``file()``.
845 result, use ``file()``.
846
846
847 The pattern without explicit kind like ``glob:`` is expected to be
847 The pattern without explicit kind like ``glob:`` is expected to be
848 relative to the current directory and match against a file exactly
848 relative to the current directory and match against a file exactly
849 for efficiency.
849 for efficiency.
850
850
851 If some linkrev points to revisions filtered by the current repoview, we'll
851 If some linkrev points to revisions filtered by the current repoview, we'll
852 work around it to return a non-filtered value.
852 work around it to return a non-filtered value.
853 """
853 """
854
854
855 # i18n: "filelog" is a keyword
855 # i18n: "filelog" is a keyword
856 pat = getstring(x, _("filelog requires a pattern"))
856 pat = getstring(x, _("filelog requires a pattern"))
857 s = set()
857 s = set()
858 cl = repo.changelog
858 cl = repo.changelog
859
859
860 if not matchmod.patkind(pat):
860 if not matchmod.patkind(pat):
861 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
861 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
862 files = [f]
862 files = [f]
863 else:
863 else:
864 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
864 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
865 files = (f for f in repo[None] if m(f))
865 files = (f for f in repo[None] if m(f))
866
866
867 for f in files:
867 for f in files:
868 backrevref = {} # final value for: filerev -> changerev
868 backrevref = {} # final value for: filerev -> changerev
869 lowestchild = {} # lowest known filerev child of a filerev
869 lowestchild = {} # lowest known filerev child of a filerev
870 delayed = [] # filerev with filtered linkrev, for post-processing
870 delayed = [] # filerev with filtered linkrev, for post-processing
871 lowesthead = None # cache for manifest content of all head revisions
871 lowesthead = None # cache for manifest content of all head revisions
872 fl = repo.file(f)
872 fl = repo.file(f)
873 for fr in list(fl):
873 for fr in list(fl):
874 rev = fl.linkrev(fr)
874 rev = fl.linkrev(fr)
875 if rev not in cl:
875 if rev not in cl:
876 # changerev pointed in linkrev is filtered
876 # changerev pointed in linkrev is filtered
877 # record it for post processing.
877 # record it for post processing.
878 delayed.append((fr, rev))
878 delayed.append((fr, rev))
879 continue
879 continue
880 for p in fl.parentrevs(fr):
880 for p in fl.parentrevs(fr):
881 if 0 <= p and p not in lowestchild:
881 if 0 <= p and p not in lowestchild:
882 lowestchild[p] = fr
882 lowestchild[p] = fr
883 backrevref[fr] = rev
883 backrevref[fr] = rev
884 s.add(rev)
884 s.add(rev)
885
885
886 # Post-processing of all filerevs we skipped because they were
886 # Post-processing of all filerevs we skipped because they were
887 # filtered. If such filerevs have known and unfiltered children, this
887 # filtered. If such filerevs have known and unfiltered children, this
888 # means they have an unfiltered appearance out there. We'll use linkrev
888 # means they have an unfiltered appearance out there. We'll use linkrev
889 # adjustment to find one of these appearances. The lowest known child
889 # adjustment to find one of these appearances. The lowest known child
890 # will be used as a starting point because it is the best upper-bound we
890 # will be used as a starting point because it is the best upper-bound we
891 # have.
891 # have.
892 #
892 #
893 # This approach will fail when an unfiltered but linkrev-shadowed
893 # This approach will fail when an unfiltered but linkrev-shadowed
894 # appearance exists in a head changeset without unfiltered filerev
894 # appearance exists in a head changeset without unfiltered filerev
895 # children anywhere.
895 # children anywhere.
896 while delayed:
896 while delayed:
897 # must be a descending iteration. To slowly fill lowest child
897 # must be a descending iteration. To slowly fill lowest child
898 # information that is of potential use by the next item.
898 # information that is of potential use by the next item.
899 fr, rev = delayed.pop()
899 fr, rev = delayed.pop()
900 lkr = rev
900 lkr = rev
901
901
902 child = lowestchild.get(fr)
902 child = lowestchild.get(fr)
903
903
904 if child is None:
904 if child is None:
905 # search for existence of this file revision in a head revision.
905 # search for existence of this file revision in a head revision.
906 # There are three possibilities:
906 # There are three possibilities:
907 # - the revision exists in a head and we can find an
907 # - the revision exists in a head and we can find an
908 # introduction from there,
908 # introduction from there,
909 # - the revision does not exist in a head because it has been
909 # - the revision does not exist in a head because it has been
910 # changed since its introduction: we would have found a child
910 # changed since its introduction: we would have found a child
911 # and be in the other 'else' clause,
911 # and be in the other 'else' clause,
912 # - all versions of the revision are hidden.
912 # - all versions of the revision are hidden.
913 if lowesthead is None:
913 if lowesthead is None:
914 lowesthead = {}
914 lowesthead = {}
915 for h in repo.heads():
915 for h in repo.heads():
916 fnode = repo[h].manifest().get(f)
916 fnode = repo[h].manifest().get(f)
917 if fnode is not None:
917 if fnode is not None:
918 lowesthead[fl.rev(fnode)] = h
918 lowesthead[fl.rev(fnode)] = h
919 headrev = lowesthead.get(fr)
919 headrev = lowesthead.get(fr)
920 if headrev is None:
920 if headrev is None:
921 # content is nowhere unfiltered
921 # content is nowhere unfiltered
922 continue
922 continue
923 rev = repo[headrev][f].introrev()
923 rev = repo[headrev][f].introrev()
924 else:
924 else:
925 # the lowest known child is a good upper bound
925 # the lowest known child is a good upper bound
926 childcrev = backrevref[child]
926 childcrev = backrevref[child]
927 # XXX this does not guarantee returning the lowest
927 # XXX this does not guarantee returning the lowest
928 # introduction of this revision, but this gives a
928 # introduction of this revision, but this gives a
929 # result which is a good start and will fit in most
929 # result which is a good start and will fit in most
930 # cases. We probably need to fix the multiple
930 # cases. We probably need to fix the multiple
931 # introductions case properly (report each
931 # introductions case properly (report each
932 # introduction, even for identical file revisions)
932 # introduction, even for identical file revisions)
933 # once and for all at some point anyway.
933 # once and for all at some point anyway.
934 for p in repo[childcrev][f].parents():
934 for p in repo[childcrev][f].parents():
935 if p.filerev() == fr:
935 if p.filerev() == fr:
936 rev = p.rev()
936 rev = p.rev()
937 break
937 break
938 if rev == lkr: # no shadowed entry found
938 if rev == lkr: # no shadowed entry found
939 # XXX This should never happen unless some manifest points
939 # XXX This should never happen unless some manifest points
940 # to biggish file revisions (like a revision that uses a
940 # to biggish file revisions (like a revision that uses a
941 # parent that never appears in the manifest ancestors)
941 # parent that never appears in the manifest ancestors)
942 continue
942 continue
943
943
944 # Fill the data for the next iteration.
944 # Fill the data for the next iteration.
945 for p in fl.parentrevs(fr):
945 for p in fl.parentrevs(fr):
946 if 0 <= p and p not in lowestchild:
946 if 0 <= p and p not in lowestchild:
947 lowestchild[p] = fr
947 lowestchild[p] = fr
948 backrevref[fr] = rev
948 backrevref[fr] = rev
949 s.add(rev)
949 s.add(rev)
950
950
951 return subset & s
951 return subset & s
952
952
953 def first(repo, subset, x):
953 def first(repo, subset, x):
954 """``first(set, [n])``
954 """``first(set, [n])``
955 An alias for limit().
955 An alias for limit().
956 """
956 """
957 return limit(repo, subset, x)
957 return limit(repo, subset, x)
958
958
959 def _follow(repo, subset, x, name, followfirst=False):
959 def _follow(repo, subset, x, name, followfirst=False):
960 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
960 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
961 c = repo['.']
961 c = repo['.']
962 if l:
962 if l:
963 x = getstring(l[0], _("%s expected a filename") % name)
963 x = getstring(l[0], _("%s expected a filename") % name)
964 if x in c:
964 if x in c:
965 cx = c[x]
965 cx = c[x]
966 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
966 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
967 # include the revision responsible for the most recent version
967 # include the revision responsible for the most recent version
968 s.add(cx.introrev())
968 s.add(cx.introrev())
969 else:
969 else:
970 return baseset()
970 return baseset()
971 else:
971 else:
972 s = _revancestors(repo, baseset([c.rev()]), followfirst)
972 s = _revancestors(repo, baseset([c.rev()]), followfirst)
973
973
974 return subset & s
974 return subset & s
975
975
976 def follow(repo, subset, x):
976 def follow(repo, subset, x):
977 """``follow([file])``
977 """``follow([file])``
978 An alias for ``::.`` (ancestors of the working copy's first parent).
978 An alias for ``::.`` (ancestors of the working copy's first parent).
979 If a filename is specified, the history of the given file is followed,
979 If a filename is specified, the history of the given file is followed,
980 including copies.
980 including copies.
981 """
981 """
982 return _follow(repo, subset, x, 'follow')
982 return _follow(repo, subset, x, 'follow')
983
983
984 def _followfirst(repo, subset, x):
984 def _followfirst(repo, subset, x):
985 # ``followfirst([file])``
985 # ``followfirst([file])``
986 # Like ``follow([file])`` but follows only the first parent of
986 # Like ``follow([file])`` but follows only the first parent of
987 # every revision or file revision.
987 # every revision or file revision.
988 return _follow(repo, subset, x, '_followfirst', followfirst=True)
988 return _follow(repo, subset, x, '_followfirst', followfirst=True)
989
989
990 def getall(repo, subset, x):
990 def getall(repo, subset, x):
991 """``all()``
991 """``all()``
992 All changesets, the same as ``0:tip``.
992 All changesets, the same as ``0:tip``.
993 """
993 """
994 # i18n: "all" is a keyword
994 # i18n: "all" is a keyword
995 getargs(x, 0, 0, _("all takes no arguments"))
995 getargs(x, 0, 0, _("all takes no arguments"))
996 return subset
996 return subset
997
997
998 def grep(repo, subset, x):
998 def grep(repo, subset, x):
999 """``grep(regex)``
999 """``grep(regex)``
1000 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1000 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1001 to ensure special escape characters are handled correctly. Unlike
1001 to ensure special escape characters are handled correctly. Unlike
1002 ``keyword(string)``, the match is case-sensitive.
1002 ``keyword(string)``, the match is case-sensitive.
1003 """
1003 """
1004 try:
1004 try:
1005 # i18n: "grep" is a keyword
1005 # i18n: "grep" is a keyword
1006 gr = re.compile(getstring(x, _("grep requires a string")))
1006 gr = re.compile(getstring(x, _("grep requires a string")))
1007 except re.error, e:
1007 except re.error, e:
1008 raise error.ParseError(_('invalid match pattern: %s') % e)
1008 raise error.ParseError(_('invalid match pattern: %s') % e)
1009
1009
1010 def matches(x):
1010 def matches(x):
1011 c = repo[x]
1011 c = repo[x]
1012 for e in c.files() + [c.user(), c.description()]:
1012 for e in c.files() + [c.user(), c.description()]:
1013 if gr.search(e):
1013 if gr.search(e):
1014 return True
1014 return True
1015 return False
1015 return False
1016
1016
1017 return subset.filter(matches)
1017 return subset.filter(matches)
1018
1018
1019 def _matchfiles(repo, subset, x):
1019 def _matchfiles(repo, subset, x):
1020 # _matchfiles takes a revset list of prefixed arguments:
1020 # _matchfiles takes a revset list of prefixed arguments:
1021 #
1021 #
1022 # [p:foo, i:bar, x:baz]
1022 # [p:foo, i:bar, x:baz]
1023 #
1023 #
1024 # builds a match object from them and filters subset. Allowed
1024 # builds a match object from them and filters subset. Allowed
1025 # prefixes are 'p:' for regular patterns, 'i:' for include
1025 # prefixes are 'p:' for regular patterns, 'i:' for include
1026 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1026 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1027 # a revision identifier, or the empty string to reference the
1027 # a revision identifier, or the empty string to reference the
1028 # working directory, from which the match object is
1028 # working directory, from which the match object is
1029 # initialized. Use 'd:' to set the default matching mode, default
1029 # initialized. Use 'd:' to set the default matching mode, default
1030 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1030 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1031
1031
1032 # i18n: "_matchfiles" is a keyword
1032 # i18n: "_matchfiles" is a keyword
1033 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1033 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
1034 pats, inc, exc = [], [], []
1034 pats, inc, exc = [], [], []
1035 rev, default = None, None
1035 rev, default = None, None
1036 for arg in l:
1036 for arg in l:
1037 # i18n: "_matchfiles" is a keyword
1037 # i18n: "_matchfiles" is a keyword
1038 s = getstring(arg, _("_matchfiles requires string arguments"))
1038 s = getstring(arg, _("_matchfiles requires string arguments"))
1039 prefix, value = s[:2], s[2:]
1039 prefix, value = s[:2], s[2:]
1040 if prefix == 'p:':
1040 if prefix == 'p:':
1041 pats.append(value)
1041 pats.append(value)
1042 elif prefix == 'i:':
1042 elif prefix == 'i:':
1043 inc.append(value)
1043 inc.append(value)
1044 elif prefix == 'x:':
1044 elif prefix == 'x:':
1045 exc.append(value)
1045 exc.append(value)
1046 elif prefix == 'r:':
1046 elif prefix == 'r:':
1047 if rev is not None:
1047 if rev is not None:
1048 # i18n: "_matchfiles" is a keyword
1048 # i18n: "_matchfiles" is a keyword
1049 raise error.ParseError(_('_matchfiles expected at most one '
1049 raise error.ParseError(_('_matchfiles expected at most one '
1050 'revision'))
1050 'revision'))
1051 if value != '': # empty means working directory; leave rev as None
1051 if value != '': # empty means working directory; leave rev as None
1052 rev = value
1052 rev = value
1053 elif prefix == 'd:':
1053 elif prefix == 'd:':
1054 if default is not None:
1054 if default is not None:
1055 # i18n: "_matchfiles" is a keyword
1055 # i18n: "_matchfiles" is a keyword
1056 raise error.ParseError(_('_matchfiles expected at most one '
1056 raise error.ParseError(_('_matchfiles expected at most one '
1057 'default mode'))
1057 'default mode'))
1058 default = value
1058 default = value
1059 else:
1059 else:
1060 # i18n: "_matchfiles" is a keyword
1060 # i18n: "_matchfiles" is a keyword
1061 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1061 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
1062 if not default:
1062 if not default:
1063 default = 'glob'
1063 default = 'glob'
1064
1064
1065 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1065 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1066 exclude=exc, ctx=repo[rev], default=default)
1066 exclude=exc, ctx=repo[rev], default=default)
1067
1067
1068 def matches(x):
1068 def matches(x):
1069 for f in repo[x].files():
1069 for f in repo[x].files():
1070 if m(f):
1070 if m(f):
1071 return True
1071 return True
1072 return False
1072 return False
1073
1073
1074 return subset.filter(matches)
1074 return subset.filter(matches)
1075
1075
1076 def hasfile(repo, subset, x):
1076 def hasfile(repo, subset, x):
1077 """``file(pattern)``
1077 """``file(pattern)``
1078 Changesets affecting files matched by pattern.
1078 Changesets affecting files matched by pattern.
1079
1079
1080 For a faster but less accurate result, consider using ``filelog()``
1080 For a faster but less accurate result, consider using ``filelog()``
1081 instead.
1081 instead.
1082
1082
1083 This predicate uses ``glob:`` as the default kind of pattern.
1083 This predicate uses ``glob:`` as the default kind of pattern.
1084 """
1084 """
1085 # i18n: "file" is a keyword
1085 # i18n: "file" is a keyword
1086 pat = getstring(x, _("file requires a pattern"))
1086 pat = getstring(x, _("file requires a pattern"))
1087 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1087 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1088
1088
1089 def head(repo, subset, x):
1089 def head(repo, subset, x):
1090 """``head()``
1090 """``head()``
1091 Changeset is a named branch head.
1091 Changeset is a named branch head.
1092 """
1092 """
1093 # i18n: "head" is a keyword
1093 # i18n: "head" is a keyword
1094 getargs(x, 0, 0, _("head takes no arguments"))
1094 getargs(x, 0, 0, _("head takes no arguments"))
1095 hs = set()
1095 hs = set()
1096 for b, ls in repo.branchmap().iteritems():
1096 for b, ls in repo.branchmap().iteritems():
1097 hs.update(repo[h].rev() for h in ls)
1097 hs.update(repo[h].rev() for h in ls)
1098 return baseset(hs).filter(subset.__contains__)
1098 return baseset(hs).filter(subset.__contains__)
1099
1099
1100 def heads(repo, subset, x):
1100 def heads(repo, subset, x):
1101 """``heads(set)``
1101 """``heads(set)``
1102 Members of set with no children in set.
1102 Members of set with no children in set.
1103 """
1103 """
1104 s = getset(repo, subset, x)
1104 s = getset(repo, subset, x)
1105 ps = parents(repo, subset, x)
1105 ps = parents(repo, subset, x)
1106 return s - ps
1106 return s - ps
1107
1107
1108 def hidden(repo, subset, x):
1108 def hidden(repo, subset, x):
1109 """``hidden()``
1109 """``hidden()``
1110 Hidden changesets.
1110 Hidden changesets.
1111 """
1111 """
1112 # i18n: "hidden" is a keyword
1112 # i18n: "hidden" is a keyword
1113 getargs(x, 0, 0, _("hidden takes no arguments"))
1113 getargs(x, 0, 0, _("hidden takes no arguments"))
1114 hiddenrevs = repoview.filterrevs(repo, 'visible')
1114 hiddenrevs = repoview.filterrevs(repo, 'visible')
1115 return subset & hiddenrevs
1115 return subset & hiddenrevs
1116
1116
1117 def keyword(repo, subset, x):
1117 def keyword(repo, subset, x):
1118 """``keyword(string)``
1118 """``keyword(string)``
1119 Search commit message, user name, and names of changed files for
1119 Search commit message, user name, and names of changed files for
1120 string. The match is case-insensitive.
1120 string. The match is case-insensitive.
1121 """
1121 """
1122 # i18n: "keyword" is a keyword
1122 # i18n: "keyword" is a keyword
1123 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1123 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1124
1124
1125 def matches(r):
1125 def matches(r):
1126 c = repo[r]
1126 c = repo[r]
1127 return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
1127 return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
1128 c.description()])
1128 c.description()])
1129
1129
1130 return subset.filter(matches)
1130 return subset.filter(matches)
1131
1131
1132 def limit(repo, subset, x):
1132 def limit(repo, subset, x):
1133 """``limit(set, [n])``
1133 """``limit(set, [n])``
1134 First n members of set, defaulting to 1.
1134 First n members of set, defaulting to 1.
1135 """
1135 """
1136 # i18n: "limit" is a keyword
1136 # i18n: "limit" is a keyword
1137 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1137 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
1138 try:
1138 try:
1139 lim = 1
1139 lim = 1
1140 if len(l) == 2:
1140 if len(l) == 2:
1141 # i18n: "limit" is a keyword
1141 # i18n: "limit" is a keyword
1142 lim = int(getstring(l[1], _("limit requires a number")))
1142 lim = int(getstring(l[1], _("limit requires a number")))
1143 except (TypeError, ValueError):
1143 except (TypeError, ValueError):
1144 # i18n: "limit" is a keyword
1144 # i18n: "limit" is a keyword
1145 raise error.ParseError(_("limit expects a number"))
1145 raise error.ParseError(_("limit expects a number"))
1146 ss = subset
1146 ss = subset
1147 os = getset(repo, spanset(repo), l[0])
1147 os = getset(repo, spanset(repo), l[0])
1148 result = []
1148 result = []
1149 it = iter(os)
1149 it = iter(os)
1150 for x in xrange(lim):
1150 for x in xrange(lim):
1151 try:
1151 try:
1152 y = it.next()
1152 y = it.next()
1153 if y in ss:
1153 if y in ss:
1154 result.append(y)
1154 result.append(y)
1155 except (StopIteration):
1155 except (StopIteration):
1156 break
1156 break
1157 return baseset(result)
1157 return baseset(result)
1158
1158
1159 def last(repo, subset, x):
1159 def last(repo, subset, x):
1160 """``last(set, [n])``
1160 """``last(set, [n])``
1161 Last n members of set, defaulting to 1.
1161 Last n members of set, defaulting to 1.
1162 """
1162 """
1163 # i18n: "last" is a keyword
1163 # i18n: "last" is a keyword
1164 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1164 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1165 try:
1165 try:
1166 lim = 1
1166 lim = 1
1167 if len(l) == 2:
1167 if len(l) == 2:
1168 # i18n: "last" is a keyword
1168 # i18n: "last" is a keyword
1169 lim = int(getstring(l[1], _("last requires a number")))
1169 lim = int(getstring(l[1], _("last requires a number")))
1170 except (TypeError, ValueError):
1170 except (TypeError, ValueError):
1171 # i18n: "last" is a keyword
1171 # i18n: "last" is a keyword
1172 raise error.ParseError(_("last expects a number"))
1172 raise error.ParseError(_("last expects a number"))
1173 ss = subset
1173 ss = subset
1174 os = getset(repo, spanset(repo), l[0])
1174 os = getset(repo, spanset(repo), l[0])
1175 os.reverse()
1175 os.reverse()
1176 result = []
1176 result = []
1177 it = iter(os)
1177 it = iter(os)
1178 for x in xrange(lim):
1178 for x in xrange(lim):
1179 try:
1179 try:
1180 y = it.next()
1180 y = it.next()
1181 if y in ss:
1181 if y in ss:
1182 result.append(y)
1182 result.append(y)
1183 except (StopIteration):
1183 except (StopIteration):
1184 break
1184 break
1185 return baseset(result)
1185 return baseset(result)
1186
1186
1187 def maxrev(repo, subset, x):
1187 def maxrev(repo, subset, x):
1188 """``max(set)``
1188 """``max(set)``
1189 Changeset with highest revision number in set.
1189 Changeset with highest revision number in set.
1190 """
1190 """
1191 os = getset(repo, spanset(repo), x)
1191 os = getset(repo, spanset(repo), x)
1192 if os:
1192 if os:
1193 m = os.max()
1193 m = os.max()
1194 if m in subset:
1194 if m in subset:
1195 return baseset([m])
1195 return baseset([m])
1196 return baseset()
1196 return baseset()
1197
1197
1198 def merge(repo, subset, x):
1198 def merge(repo, subset, x):
1199 """``merge()``
1199 """``merge()``
1200 Changeset is a merge changeset.
1200 Changeset is a merge changeset.
1201 """
1201 """
1202 # i18n: "merge" is a keyword
1202 # i18n: "merge" is a keyword
1203 getargs(x, 0, 0, _("merge takes no arguments"))
1203 getargs(x, 0, 0, _("merge takes no arguments"))
1204 cl = repo.changelog
1204 cl = repo.changelog
1205 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1205 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
1206
1206
1207 def branchpoint(repo, subset, x):
1207 def branchpoint(repo, subset, x):
1208 """``branchpoint()``
1208 """``branchpoint()``
1209 Changesets with more than one child.
1209 Changesets with more than one child.
1210 """
1210 """
1211 # i18n: "branchpoint" is a keyword
1211 # i18n: "branchpoint" is a keyword
1212 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1212 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1213 cl = repo.changelog
1213 cl = repo.changelog
1214 if not subset:
1214 if not subset:
1215 return baseset()
1215 return baseset()
1216 baserev = min(subset)
1216 baserev = min(subset)
1217 parentscount = [0]*(len(repo) - baserev)
1217 parentscount = [0]*(len(repo) - baserev)
1218 for r in cl.revs(start=baserev + 1):
1218 for r in cl.revs(start=baserev + 1):
1219 for p in cl.parentrevs(r):
1219 for p in cl.parentrevs(r):
1220 if p >= baserev:
1220 if p >= baserev:
1221 parentscount[p - baserev] += 1
1221 parentscount[p - baserev] += 1
1222 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1222 return subset.filter(lambda r: parentscount[r - baserev] > 1)
1223
1223
1224 def minrev(repo, subset, x):
1224 def minrev(repo, subset, x):
1225 """``min(set)``
1225 """``min(set)``
1226 Changeset with lowest revision number in set.
1226 Changeset with lowest revision number in set.
1227 """
1227 """
1228 os = getset(repo, spanset(repo), x)
1228 os = getset(repo, spanset(repo), x)
1229 if os:
1229 if os:
1230 m = os.min()
1230 m = os.min()
1231 if m in subset:
1231 if m in subset:
1232 return baseset([m])
1232 return baseset([m])
1233 return baseset()
1233 return baseset()
1234
1234
1235 def modifies(repo, subset, x):
1235 def modifies(repo, subset, x):
1236 """``modifies(pattern)``
1236 """``modifies(pattern)``
1237 Changesets modifying files matched by pattern.
1237 Changesets modifying files matched by pattern.
1238
1238
1239 The pattern without explicit kind like ``glob:`` is expected to be
1239 The pattern without explicit kind like ``glob:`` is expected to be
1240 relative to the current directory and match against a file or a
1240 relative to the current directory and match against a file or a
1241 directory.
1241 directory.
1242 """
1242 """
1243 # i18n: "modifies" is a keyword
1243 # i18n: "modifies" is a keyword
1244 pat = getstring(x, _("modifies requires a pattern"))
1244 pat = getstring(x, _("modifies requires a pattern"))
1245 return checkstatus(repo, subset, pat, 0)
1245 return checkstatus(repo, subset, pat, 0)
1246
1246
1247 def named(repo, subset, x):
1247 def named(repo, subset, x):
1248 """``named(namespace)``
1248 """``named(namespace)``
1249 The changesets in a given namespace.
1249 The changesets in a given namespace.
1250
1250
1251 If `namespace` starts with `re:`, the remainder of the string is treated as
1251 If `namespace` starts with `re:`, the remainder of the string is treated as
1252 a regular expression. To match a namespace that actually starts with `re:`,
1252 a regular expression. To match a namespace that actually starts with `re:`,
1253 use the prefix `literal:`.
1253 use the prefix `literal:`.
1254 """
1254 """
1255 # i18n: "named" is a keyword
1255 # i18n: "named" is a keyword
1256 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1256 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1257
1257
1258 ns = getstring(args[0],
1258 ns = getstring(args[0],
1259 # i18n: "named" is a keyword
1259 # i18n: "named" is a keyword
1260 _('the argument to named must be a string'))
1260 _('the argument to named must be a string'))
1261 kind, pattern, matcher = _stringmatcher(ns)
1261 kind, pattern, matcher = _stringmatcher(ns)
1262 namespaces = set()
1262 namespaces = set()
1263 if kind == 'literal':
1263 if kind == 'literal':
1264 if pattern not in repo.names:
1264 if pattern not in repo.names:
1265 raise util.Abort(_("namespace '%s' does not exist") % ns)
1265 raise util.Abort(_("namespace '%s' does not exist") % ns)
1266 namespaces.add(repo.names[pattern])
1266 namespaces.add(repo.names[pattern])
1267 else:
1267 else:
1268 for name, ns in repo.names.iteritems():
1268 for name, ns in repo.names.iteritems():
1269 if matcher(name):
1269 if matcher(name):
1270 namespaces.add(ns)
1270 namespaces.add(ns)
1271 if not namespaces:
1271 if not namespaces:
1272 raise util.Abort(_("no namespace exists that match '%s'")
1272 raise util.Abort(_("no namespace exists that match '%s'")
1273 % pattern)
1273 % pattern)
1274
1274
1275 names = set()
1275 names = set()
1276 for ns in namespaces:
1276 for ns in namespaces:
1277 for name in ns.listnames(repo):
1277 for name in ns.listnames(repo):
1278 names.update(ns.nodes(repo, name))
1278 names.update(ns.nodes(repo, name))
1279
1279
1280 names -= set([node.nullrev])
1280 names -= set([node.nullrev])
1281 return subset & names
1281 return subset & names
1282
1282
1283 def node_(repo, subset, x):
1283 def node_(repo, subset, x):
1284 """``id(string)``
1284 """``id(string)``
1285 Revision non-ambiguously specified by the given hex string prefix.
1285 Revision non-ambiguously specified by the given hex string prefix.
1286 """
1286 """
1287 # i18n: "id" is a keyword
1287 # i18n: "id" is a keyword
1288 l = getargs(x, 1, 1, _("id requires one argument"))
1288 l = getargs(x, 1, 1, _("id requires one argument"))
1289 # i18n: "id" is a keyword
1289 # i18n: "id" is a keyword
1290 n = getstring(l[0], _("id requires a string"))
1290 n = getstring(l[0], _("id requires a string"))
1291 if len(n) == 40:
1291 if len(n) == 40:
1292 rn = repo[n].rev()
1292 rn = repo[n].rev()
1293 else:
1293 else:
1294 rn = None
1294 rn = None
1295 pm = repo.changelog._partialmatch(n)
1295 pm = repo.changelog._partialmatch(n)
1296 if pm is not None:
1296 if pm is not None:
1297 rn = repo.changelog.rev(pm)
1297 rn = repo.changelog.rev(pm)
1298
1298
1299 if rn is None:
1299 if rn is None:
1300 return baseset()
1300 return baseset()
1301 result = baseset([rn])
1301 result = baseset([rn])
1302 return result & subset
1302 return result & subset
1303
1303
1304 def obsolete(repo, subset, x):
1304 def obsolete(repo, subset, x):
1305 """``obsolete()``
1305 """``obsolete()``
1306 Mutable changeset with a newer version."""
1306 Mutable changeset with a newer version."""
1307 # i18n: "obsolete" is a keyword
1307 # i18n: "obsolete" is a keyword
1308 getargs(x, 0, 0, _("obsolete takes no arguments"))
1308 getargs(x, 0, 0, _("obsolete takes no arguments"))
1309 obsoletes = obsmod.getrevs(repo, 'obsolete')
1309 obsoletes = obsmod.getrevs(repo, 'obsolete')
1310 return subset & obsoletes
1310 return subset & obsoletes
1311
1311
1312 def only(repo, subset, x):
1312 def only(repo, subset, x):
1313 """``only(set, [set])``
1313 """``only(set, [set])``
1314 Changesets that are ancestors of the first set that are not ancestors
1314 Changesets that are ancestors of the first set that are not ancestors
1315 of any other head in the repo. If a second set is specified, the result
1315 of any other head in the repo. If a second set is specified, the result
1316 is ancestors of the first set that are not ancestors of the second set
1316 is ancestors of the first set that are not ancestors of the second set
1317 (i.e. ::<set1> - ::<set2>).
1317 (i.e. ::<set1> - ::<set2>).
1318 """
1318 """
1319 cl = repo.changelog
1319 cl = repo.changelog
1320 # i18n: "only" is a keyword
1320 # i18n: "only" is a keyword
1321 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1321 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1322 include = getset(repo, spanset(repo), args[0])
1322 include = getset(repo, spanset(repo), args[0])
1323 if len(args) == 1:
1323 if len(args) == 1:
1324 if not include:
1324 if not include:
1325 return baseset()
1325 return baseset()
1326
1326
1327 descendants = set(_revdescendants(repo, include, False))
1327 descendants = set(_revdescendants(repo, include, False))
1328 exclude = [rev for rev in cl.headrevs()
1328 exclude = [rev for rev in cl.headrevs()
1329 if not rev in descendants and not rev in include]
1329 if not rev in descendants and not rev in include]
1330 else:
1330 else:
1331 exclude = getset(repo, spanset(repo), args[1])
1331 exclude = getset(repo, spanset(repo), args[1])
1332
1332
1333 results = set(cl.findmissingrevs(common=exclude, heads=include))
1333 results = set(cl.findmissingrevs(common=exclude, heads=include))
1334 return subset & results
1334 return subset & results
1335
1335
1336 def origin(repo, subset, x):
1336 def origin(repo, subset, x):
1337 """``origin([set])``
1337 """``origin([set])``
1338 Changesets that were specified as a source for the grafts, transplants or
1338 Changesets that were specified as a source for the grafts, transplants or
1339 rebases that created the given revisions. Omitting the optional set is the
1339 rebases that created the given revisions. Omitting the optional set is the
1340 same as passing all(). If a changeset created by these operations is itself
1340 same as passing all(). If a changeset created by these operations is itself
1341 specified as a source for one of these operations, only the source changeset
1341 specified as a source for one of these operations, only the source changeset
1342 for the first operation is selected.
1342 for the first operation is selected.
1343 """
1343 """
1344 if x is not None:
1344 if x is not None:
1345 dests = getset(repo, spanset(repo), x)
1345 dests = getset(repo, spanset(repo), x)
1346 else:
1346 else:
1347 dests = getall(repo, spanset(repo), x)
1347 dests = getall(repo, spanset(repo), x)
1348
1348
1349 def _firstsrc(rev):
1349 def _firstsrc(rev):
1350 src = _getrevsource(repo, rev)
1350 src = _getrevsource(repo, rev)
1351 if src is None:
1351 if src is None:
1352 return None
1352 return None
1353
1353
1354 while True:
1354 while True:
1355 prev = _getrevsource(repo, src)
1355 prev = _getrevsource(repo, src)
1356
1356
1357 if prev is None:
1357 if prev is None:
1358 return src
1358 return src
1359 src = prev
1359 src = prev
1360
1360
1361 o = set([_firstsrc(r) for r in dests])
1361 o = set([_firstsrc(r) for r in dests])
1362 o -= set([None])
1362 o -= set([None])
1363 return subset & o
1363 return subset & o
1364
1364
1365 def outgoing(repo, subset, x):
1365 def outgoing(repo, subset, x):
1366 """``outgoing([path])``
1366 """``outgoing([path])``
1367 Changesets not found in the specified destination repository, or the
1367 Changesets not found in the specified destination repository, or the
1368 default push location.
1368 default push location.
1369 """
1369 """
1370 import hg # avoid start-up nasties
1370 import hg # avoid start-up nasties
1371 # i18n: "outgoing" is a keyword
1371 # i18n: "outgoing" is a keyword
1372 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1372 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1373 # i18n: "outgoing" is a keyword
1373 # i18n: "outgoing" is a keyword
1374 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1374 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1375 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1375 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1376 dest, branches = hg.parseurl(dest)
1376 dest, branches = hg.parseurl(dest)
1377 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1377 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1378 if revs:
1378 if revs:
1379 revs = [repo.lookup(rev) for rev in revs]
1379 revs = [repo.lookup(rev) for rev in revs]
1380 other = hg.peer(repo, {}, dest)
1380 other = hg.peer(repo, {}, dest)
1381 repo.ui.pushbuffer()
1381 repo.ui.pushbuffer()
1382 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1382 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1383 repo.ui.popbuffer()
1383 repo.ui.popbuffer()
1384 cl = repo.changelog
1384 cl = repo.changelog
1385 o = set([cl.rev(r) for r in outgoing.missing])
1385 o = set([cl.rev(r) for r in outgoing.missing])
1386 return subset & o
1386 return subset & o
1387
1387
1388 def p1(repo, subset, x):
1388 def p1(repo, subset, x):
1389 """``p1([set])``
1389 """``p1([set])``
1390 First parent of changesets in set, or the working directory.
1390 First parent of changesets in set, or the working directory.
1391 """
1391 """
1392 if x is None:
1392 if x is None:
1393 p = repo[x].p1().rev()
1393 p = repo[x].p1().rev()
1394 if p >= 0:
1394 if p >= 0:
1395 return subset & baseset([p])
1395 return subset & baseset([p])
1396 return baseset()
1396 return baseset()
1397
1397
1398 ps = set()
1398 ps = set()
1399 cl = repo.changelog
1399 cl = repo.changelog
1400 for r in getset(repo, spanset(repo), x):
1400 for r in getset(repo, spanset(repo), x):
1401 ps.add(cl.parentrevs(r)[0])
1401 ps.add(cl.parentrevs(r)[0])
1402 ps -= set([node.nullrev])
1402 ps -= set([node.nullrev])
1403 return subset & ps
1403 return subset & ps
1404
1404
1405 def p2(repo, subset, x):
1405 def p2(repo, subset, x):
1406 """``p2([set])``
1406 """``p2([set])``
1407 Second parent of changesets in set, or the working directory.
1407 Second parent of changesets in set, or the working directory.
1408 """
1408 """
1409 if x is None:
1409 if x is None:
1410 ps = repo[x].parents()
1410 ps = repo[x].parents()
1411 try:
1411 try:
1412 p = ps[1].rev()
1412 p = ps[1].rev()
1413 if p >= 0:
1413 if p >= 0:
1414 return subset & baseset([p])
1414 return subset & baseset([p])
1415 return baseset()
1415 return baseset()
1416 except IndexError:
1416 except IndexError:
1417 return baseset()
1417 return baseset()
1418
1418
1419 ps = set()
1419 ps = set()
1420 cl = repo.changelog
1420 cl = repo.changelog
1421 for r in getset(repo, spanset(repo), x):
1421 for r in getset(repo, spanset(repo), x):
1422 ps.add(cl.parentrevs(r)[1])
1422 ps.add(cl.parentrevs(r)[1])
1423 ps -= set([node.nullrev])
1423 ps -= set([node.nullrev])
1424 return subset & ps
1424 return subset & ps
1425
1425
1426 def parents(repo, subset, x):
1426 def parents(repo, subset, x):
1427 """``parents([set])``
1427 """``parents([set])``
1428 The set of all parents for all changesets in set, or the working directory.
1428 The set of all parents for all changesets in set, or the working directory.
1429 """
1429 """
1430 if x is None:
1430 if x is None:
1431 ps = set(p.rev() for p in repo[x].parents())
1431 ps = set(p.rev() for p in repo[x].parents())
1432 else:
1432 else:
1433 ps = set()
1433 ps = set()
1434 cl = repo.changelog
1434 cl = repo.changelog
1435 for r in getset(repo, spanset(repo), x):
1435 for r in getset(repo, spanset(repo), x):
1436 ps.update(cl.parentrevs(r))
1436 ps.update(cl.parentrevs(r))
1437 ps -= set([node.nullrev])
1437 ps -= set([node.nullrev])
1438 return subset & ps
1438 return subset & ps
1439
1439
1440 def parentspec(repo, subset, x, n):
1440 def parentspec(repo, subset, x, n):
1441 """``set^0``
1441 """``set^0``
1442 The set.
1442 The set.
1443 ``set^1`` (or ``set^``), ``set^2``
1443 ``set^1`` (or ``set^``), ``set^2``
1444 First or second parent, respectively, of all changesets in set.
1444 First or second parent, respectively, of all changesets in set.
1445 """
1445 """
1446 try:
1446 try:
1447 n = int(n[1])
1447 n = int(n[1])
1448 if n not in (0, 1, 2):
1448 if n not in (0, 1, 2):
1449 raise ValueError
1449 raise ValueError
1450 except (TypeError, ValueError):
1450 except (TypeError, ValueError):
1451 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1451 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1452 ps = set()
1452 ps = set()
1453 cl = repo.changelog
1453 cl = repo.changelog
1454 for r in getset(repo, fullreposet(repo), x):
1454 for r in getset(repo, fullreposet(repo), x):
1455 if n == 0:
1455 if n == 0:
1456 ps.add(r)
1456 ps.add(r)
1457 elif n == 1:
1457 elif n == 1:
1458 ps.add(cl.parentrevs(r)[0])
1458 ps.add(cl.parentrevs(r)[0])
1459 elif n == 2:
1459 elif n == 2:
1460 parents = cl.parentrevs(r)
1460 parents = cl.parentrevs(r)
1461 if len(parents) > 1:
1461 if len(parents) > 1:
1462 ps.add(parents[1])
1462 ps.add(parents[1])
1463 return subset & ps
1463 return subset & ps
1464
1464
1465 def present(repo, subset, x):
1465 def present(repo, subset, x):
1466 """``present(set)``
1466 """``present(set)``
1467 An empty set, if any revision in set isn't found; otherwise,
1467 An empty set, if any revision in set isn't found; otherwise,
1468 all revisions in set.
1468 all revisions in set.
1469
1469
1470 If any of specified revisions is not present in the local repository,
1470 If any of specified revisions is not present in the local repository,
1471 the query is normally aborted. But this predicate allows the query
1471 the query is normally aborted. But this predicate allows the query
1472 to continue even in such cases.
1472 to continue even in such cases.
1473 """
1473 """
1474 try:
1474 try:
1475 return getset(repo, subset, x)
1475 return getset(repo, subset, x)
1476 except error.RepoLookupError:
1476 except error.RepoLookupError:
1477 return baseset()
1477 return baseset()
1478
1478
1479 def public(repo, subset, x):
1479 def public(repo, subset, x):
1480 """``public()``
1480 """``public()``
1481 Changeset in public phase."""
1481 Changeset in public phase."""
1482 # i18n: "public" is a keyword
1482 # i18n: "public" is a keyword
1483 getargs(x, 0, 0, _("public takes no arguments"))
1483 getargs(x, 0, 0, _("public takes no arguments"))
1484 phase = repo._phasecache.phase
1484 phase = repo._phasecache.phase
1485 target = phases.public
1485 target = phases.public
1486 condition = lambda r: phase(repo, r) == target
1486 condition = lambda r: phase(repo, r) == target
1487 return subset.filter(condition, cache=False)
1487 return subset.filter(condition, cache=False)
1488
1488
1489 def remote(repo, subset, x):
1489 def remote(repo, subset, x):
1490 """``remote([id [,path]])``
1490 """``remote([id [,path]])``
1491 Local revision that corresponds to the given identifier in a
1491 Local revision that corresponds to the given identifier in a
1492 remote repository, if present. Here, the '.' identifier is a
1492 remote repository, if present. Here, the '.' identifier is a
1493 synonym for the current local branch.
1493 synonym for the current local branch.
1494 """
1494 """
1495
1495
1496 import hg # avoid start-up nasties
1496 import hg # avoid start-up nasties
1497 # i18n: "remote" is a keyword
1497 # i18n: "remote" is a keyword
1498 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1498 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
1499
1499
1500 q = '.'
1500 q = '.'
1501 if len(l) > 0:
1501 if len(l) > 0:
1502 # i18n: "remote" is a keyword
1502 # i18n: "remote" is a keyword
1503 q = getstring(l[0], _("remote requires a string id"))
1503 q = getstring(l[0], _("remote requires a string id"))
1504 if q == '.':
1504 if q == '.':
1505 q = repo['.'].branch()
1505 q = repo['.'].branch()
1506
1506
1507 dest = ''
1507 dest = ''
1508 if len(l) > 1:
1508 if len(l) > 1:
1509 # i18n: "remote" is a keyword
1509 # i18n: "remote" is a keyword
1510 dest = getstring(l[1], _("remote requires a repository path"))
1510 dest = getstring(l[1], _("remote requires a repository path"))
1511 dest = repo.ui.expandpath(dest or 'default')
1511 dest = repo.ui.expandpath(dest or 'default')
1512 dest, branches = hg.parseurl(dest)
1512 dest, branches = hg.parseurl(dest)
1513 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1513 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1514 if revs:
1514 if revs:
1515 revs = [repo.lookup(rev) for rev in revs]
1515 revs = [repo.lookup(rev) for rev in revs]
1516 other = hg.peer(repo, {}, dest)
1516 other = hg.peer(repo, {}, dest)
1517 n = other.lookup(q)
1517 n = other.lookup(q)
1518 if n in repo:
1518 if n in repo:
1519 r = repo[n].rev()
1519 r = repo[n].rev()
1520 if r in subset:
1520 if r in subset:
1521 return baseset([r])
1521 return baseset([r])
1522 return baseset()
1522 return baseset()
1523
1523
1524 def removes(repo, subset, x):
1524 def removes(repo, subset, x):
1525 """``removes(pattern)``
1525 """``removes(pattern)``
1526 Changesets which remove files matching pattern.
1526 Changesets which remove files matching pattern.
1527
1527
1528 The pattern without explicit kind like ``glob:`` is expected to be
1528 The pattern without explicit kind like ``glob:`` is expected to be
1529 relative to the current directory and match against a file or a
1529 relative to the current directory and match against a file or a
1530 directory.
1530 directory.
1531 """
1531 """
1532 # i18n: "removes" is a keyword
1532 # i18n: "removes" is a keyword
1533 pat = getstring(x, _("removes requires a pattern"))
1533 pat = getstring(x, _("removes requires a pattern"))
1534 return checkstatus(repo, subset, pat, 2)
1534 return checkstatus(repo, subset, pat, 2)
1535
1535
1536 def rev(repo, subset, x):
1536 def rev(repo, subset, x):
1537 """``rev(number)``
1537 """``rev(number)``
1538 Revision with the given numeric identifier.
1538 Revision with the given numeric identifier.
1539 """
1539 """
1540 # i18n: "rev" is a keyword
1540 # i18n: "rev" is a keyword
1541 l = getargs(x, 1, 1, _("rev requires one argument"))
1541 l = getargs(x, 1, 1, _("rev requires one argument"))
1542 try:
1542 try:
1543 # i18n: "rev" is a keyword
1543 # i18n: "rev" is a keyword
1544 l = int(getstring(l[0], _("rev requires a number")))
1544 l = int(getstring(l[0], _("rev requires a number")))
1545 except (TypeError, ValueError):
1545 except (TypeError, ValueError):
1546 # i18n: "rev" is a keyword
1546 # i18n: "rev" is a keyword
1547 raise error.ParseError(_("rev expects a number"))
1547 raise error.ParseError(_("rev expects a number"))
1548 if l not in fullreposet(repo) and l != node.nullrev:
1548 if l not in fullreposet(repo) and l != node.nullrev:
1549 return baseset()
1549 return baseset()
1550 return subset & baseset([l])
1550 return subset & baseset([l])
1551
1551
1552 def matching(repo, subset, x):
1552 def matching(repo, subset, x):
1553 """``matching(revision [, field])``
1553 """``matching(revision [, field])``
1554 Changesets in which a given set of fields match the set of fields in the
1554 Changesets in which a given set of fields match the set of fields in the
1555 selected revision or set.
1555 selected revision or set.
1556
1556
1557 To match more than one field pass the list of fields to match separated
1557 To match more than one field pass the list of fields to match separated
1558 by spaces (e.g. ``author description``).
1558 by spaces (e.g. ``author description``).
1559
1559
1560 Valid fields are most regular revision fields and some special fields.
1560 Valid fields are most regular revision fields and some special fields.
1561
1561
1562 Regular revision fields are ``description``, ``author``, ``branch``,
1562 Regular revision fields are ``description``, ``author``, ``branch``,
1563 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1563 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1564 and ``diff``.
1564 and ``diff``.
1565 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1565 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1566 contents of the revision. Two revisions matching their ``diff`` will
1566 contents of the revision. Two revisions matching their ``diff`` will
1567 also match their ``files``.
1567 also match their ``files``.
1568
1568
1569 Special fields are ``summary`` and ``metadata``:
1569 Special fields are ``summary`` and ``metadata``:
1570 ``summary`` matches the first line of the description.
1570 ``summary`` matches the first line of the description.
1571 ``metadata`` is equivalent to matching ``description user date``
1571 ``metadata`` is equivalent to matching ``description user date``
1572 (i.e. it matches the main metadata fields).
1572 (i.e. it matches the main metadata fields).
1573
1573
1574 ``metadata`` is the default field which is used when no fields are
1574 ``metadata`` is the default field which is used when no fields are
1575 specified. You can match more than one field at a time.
1575 specified. You can match more than one field at a time.
1576 """
1576 """
1577 # i18n: "matching" is a keyword
1577 # i18n: "matching" is a keyword
1578 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1578 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1579
1579
1580 revs = getset(repo, fullreposet(repo), l[0])
1580 revs = getset(repo, fullreposet(repo), l[0])
1581
1581
1582 fieldlist = ['metadata']
1582 fieldlist = ['metadata']
1583 if len(l) > 1:
1583 if len(l) > 1:
1584 fieldlist = getstring(l[1],
1584 fieldlist = getstring(l[1],
1585 # i18n: "matching" is a keyword
1585 # i18n: "matching" is a keyword
1586 _("matching requires a string "
1586 _("matching requires a string "
1587 "as its second argument")).split()
1587 "as its second argument")).split()
1588
1588
1589 # Make sure that there are no repeated fields,
1589 # Make sure that there are no repeated fields,
1590 # expand the 'special' 'metadata' field type
1590 # expand the 'special' 'metadata' field type
1591 # and check the 'files' whenever we check the 'diff'
1591 # and check the 'files' whenever we check the 'diff'
1592 fields = []
1592 fields = []
1593 for field in fieldlist:
1593 for field in fieldlist:
1594 if field == 'metadata':
1594 if field == 'metadata':
1595 fields += ['user', 'description', 'date']
1595 fields += ['user', 'description', 'date']
1596 elif field == 'diff':
1596 elif field == 'diff':
1597 # a revision matching the diff must also match the files
1597 # a revision matching the diff must also match the files
1598 # since matching the diff is very costly, make sure to
1598 # since matching the diff is very costly, make sure to
1599 # also match the files first
1599 # also match the files first
1600 fields += ['files', 'diff']
1600 fields += ['files', 'diff']
1601 else:
1601 else:
1602 if field == 'author':
1602 if field == 'author':
1603 field = 'user'
1603 field = 'user'
1604 fields.append(field)
1604 fields.append(field)
1605 fields = set(fields)
1605 fields = set(fields)
1606 if 'summary' in fields and 'description' in fields:
1606 if 'summary' in fields and 'description' in fields:
1607 # If a revision matches its description it also matches its summary
1607 # If a revision matches its description it also matches its summary
1608 fields.discard('summary')
1608 fields.discard('summary')
1609
1609
1610 # We may want to match more than one field
1610 # We may want to match more than one field
1611 # Not all fields take the same amount of time to be matched
1611 # Not all fields take the same amount of time to be matched
1612 # Sort the selected fields in order of increasing matching cost
1612 # Sort the selected fields in order of increasing matching cost
1613 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1613 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1614 'files', 'description', 'substate', 'diff']
1614 'files', 'description', 'substate', 'diff']
1615 def fieldkeyfunc(f):
1615 def fieldkeyfunc(f):
1616 try:
1616 try:
1617 return fieldorder.index(f)
1617 return fieldorder.index(f)
1618 except ValueError:
1618 except ValueError:
1619 # assume an unknown field is very costly
1619 # assume an unknown field is very costly
1620 return len(fieldorder)
1620 return len(fieldorder)
1621 fields = list(fields)
1621 fields = list(fields)
1622 fields.sort(key=fieldkeyfunc)
1622 fields.sort(key=fieldkeyfunc)
1623
1623
1624 # Each field will be matched with its own "getfield" function
1624 # Each field will be matched with its own "getfield" function
1625 # which will be added to the getfieldfuncs array of functions
1625 # which will be added to the getfieldfuncs array of functions
1626 getfieldfuncs = []
1626 getfieldfuncs = []
1627 _funcs = {
1627 _funcs = {
1628 'user': lambda r: repo[r].user(),
1628 'user': lambda r: repo[r].user(),
1629 'branch': lambda r: repo[r].branch(),
1629 'branch': lambda r: repo[r].branch(),
1630 'date': lambda r: repo[r].date(),
1630 'date': lambda r: repo[r].date(),
1631 'description': lambda r: repo[r].description(),
1631 'description': lambda r: repo[r].description(),
1632 'files': lambda r: repo[r].files(),
1632 'files': lambda r: repo[r].files(),
1633 'parents': lambda r: repo[r].parents(),
1633 'parents': lambda r: repo[r].parents(),
1634 'phase': lambda r: repo[r].phase(),
1634 'phase': lambda r: repo[r].phase(),
1635 'substate': lambda r: repo[r].substate,
1635 'substate': lambda r: repo[r].substate,
1636 'summary': lambda r: repo[r].description().splitlines()[0],
1636 'summary': lambda r: repo[r].description().splitlines()[0],
1637 'diff': lambda r: list(repo[r].diff(git=True),)
1637 'diff': lambda r: list(repo[r].diff(git=True),)
1638 }
1638 }
1639 for info in fields:
1639 for info in fields:
1640 getfield = _funcs.get(info, None)
1640 getfield = _funcs.get(info, None)
1641 if getfield is None:
1641 if getfield is None:
1642 raise error.ParseError(
1642 raise error.ParseError(
1643 # i18n: "matching" is a keyword
1643 # i18n: "matching" is a keyword
1644 _("unexpected field name passed to matching: %s") % info)
1644 _("unexpected field name passed to matching: %s") % info)
1645 getfieldfuncs.append(getfield)
1645 getfieldfuncs.append(getfield)
1646 # convert the getfield array of functions into a "getinfo" function
1646 # convert the getfield array of functions into a "getinfo" function
1647 # which returns an array of field values (or a single value if there
1647 # which returns an array of field values (or a single value if there
1648 # is only one field to match)
1648 # is only one field to match)
1649 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1649 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1650
1650
1651 def matches(x):
1651 def matches(x):
1652 for rev in revs:
1652 for rev in revs:
1653 target = getinfo(rev)
1653 target = getinfo(rev)
1654 match = True
1654 match = True
1655 for n, f in enumerate(getfieldfuncs):
1655 for n, f in enumerate(getfieldfuncs):
1656 if target[n] != f(x):
1656 if target[n] != f(x):
1657 match = False
1657 match = False
1658 if match:
1658 if match:
1659 return True
1659 return True
1660 return False
1660 return False
1661
1661
1662 return subset.filter(matches)
1662 return subset.filter(matches)
1663
1663
1664 def reverse(repo, subset, x):
1664 def reverse(repo, subset, x):
1665 """``reverse(set)``
1665 """``reverse(set)``
1666 Reverse order of set.
1666 Reverse order of set.
1667 """
1667 """
1668 l = getset(repo, subset, x)
1668 l = getset(repo, subset, x)
1669 l.reverse()
1669 l.reverse()
1670 return l
1670 return l
1671
1671
1672 def roots(repo, subset, x):
1672 def roots(repo, subset, x):
1673 """``roots(set)``
1673 """``roots(set)``
1674 Changesets in set with no parent changeset in set.
1674 Changesets in set with no parent changeset in set.
1675 """
1675 """
1676 s = getset(repo, spanset(repo), x)
1676 s = getset(repo, spanset(repo), x)
1677 subset = baseset([r for r in s if r in subset])
1677 subset = baseset([r for r in s if r in subset])
1678 cs = _children(repo, subset, s)
1678 cs = _children(repo, subset, s)
1679 return subset - cs
1679 return subset - cs
1680
1680
1681 def secret(repo, subset, x):
1681 def secret(repo, subset, x):
1682 """``secret()``
1682 """``secret()``
1683 Changeset in secret phase."""
1683 Changeset in secret phase."""
1684 # i18n: "secret" is a keyword
1684 # i18n: "secret" is a keyword
1685 getargs(x, 0, 0, _("secret takes no arguments"))
1685 getargs(x, 0, 0, _("secret takes no arguments"))
1686 phase = repo._phasecache.phase
1686 phase = repo._phasecache.phase
1687 target = phases.secret
1687 target = phases.secret
1688 condition = lambda r: phase(repo, r) == target
1688 condition = lambda r: phase(repo, r) == target
1689 return subset.filter(condition, cache=False)
1689 return subset.filter(condition, cache=False)
1690
1690
1691 def sort(repo, subset, x):
1691 def sort(repo, subset, x):
1692 """``sort(set[, [-]key...])``
1692 """``sort(set[, [-]key...])``
1693 Sort set by keys. The default sort order is ascending, specify a key
1693 Sort set by keys. The default sort order is ascending, specify a key
1694 as ``-key`` to sort in descending order.
1694 as ``-key`` to sort in descending order.
1695
1695
1696 The keys can be:
1696 The keys can be:
1697
1697
1698 - ``rev`` for the revision number,
1698 - ``rev`` for the revision number,
1699 - ``branch`` for the branch name,
1699 - ``branch`` for the branch name,
1700 - ``desc`` for the commit message (description),
1700 - ``desc`` for the commit message (description),
1701 - ``user`` for user name (``author`` can be used as an alias),
1701 - ``user`` for user name (``author`` can be used as an alias),
1702 - ``date`` for the commit date
1702 - ``date`` for the commit date
1703 """
1703 """
1704 # i18n: "sort" is a keyword
1704 # i18n: "sort" is a keyword
1705 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1705 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1706 keys = "rev"
1706 keys = "rev"
1707 if len(l) == 2:
1707 if len(l) == 2:
1708 # i18n: "sort" is a keyword
1708 # i18n: "sort" is a keyword
1709 keys = getstring(l[1], _("sort spec must be a string"))
1709 keys = getstring(l[1], _("sort spec must be a string"))
1710
1710
1711 s = l[0]
1711 s = l[0]
1712 keys = keys.split()
1712 keys = keys.split()
1713 l = []
1713 l = []
1714 def invert(s):
1714 def invert(s):
1715 return "".join(chr(255 - ord(c)) for c in s)
1715 return "".join(chr(255 - ord(c)) for c in s)
1716 revs = getset(repo, subset, s)
1716 revs = getset(repo, subset, s)
1717 if keys == ["rev"]:
1717 if keys == ["rev"]:
1718 revs.sort()
1718 revs.sort()
1719 return revs
1719 return revs
1720 elif keys == ["-rev"]:
1720 elif keys == ["-rev"]:
1721 revs.sort(reverse=True)
1721 revs.sort(reverse=True)
1722 return revs
1722 return revs
1723 for r in revs:
1723 for r in revs:
1724 c = repo[r]
1724 c = repo[r]
1725 e = []
1725 e = []
1726 for k in keys:
1726 for k in keys:
1727 if k == 'rev':
1727 if k == 'rev':
1728 e.append(r)
1728 e.append(r)
1729 elif k == '-rev':
1729 elif k == '-rev':
1730 e.append(-r)
1730 e.append(-r)
1731 elif k == 'branch':
1731 elif k == 'branch':
1732 e.append(c.branch())
1732 e.append(c.branch())
1733 elif k == '-branch':
1733 elif k == '-branch':
1734 e.append(invert(c.branch()))
1734 e.append(invert(c.branch()))
1735 elif k == 'desc':
1735 elif k == 'desc':
1736 e.append(c.description())
1736 e.append(c.description())
1737 elif k == '-desc':
1737 elif k == '-desc':
1738 e.append(invert(c.description()))
1738 e.append(invert(c.description()))
1739 elif k in 'user author':
1739 elif k in 'user author':
1740 e.append(c.user())
1740 e.append(c.user())
1741 elif k in '-user -author':
1741 elif k in '-user -author':
1742 e.append(invert(c.user()))
1742 e.append(invert(c.user()))
1743 elif k == 'date':
1743 elif k == 'date':
1744 e.append(c.date()[0])
1744 e.append(c.date()[0])
1745 elif k == '-date':
1745 elif k == '-date':
1746 e.append(-c.date()[0])
1746 e.append(-c.date()[0])
1747 else:
1747 else:
1748 raise error.ParseError(_("unknown sort key %r") % k)
1748 raise error.ParseError(_("unknown sort key %r") % k)
1749 e.append(r)
1749 e.append(r)
1750 l.append(e)
1750 l.append(e)
1751 l.sort()
1751 l.sort()
1752 return baseset([e[-1] for e in l])
1752 return baseset([e[-1] for e in l])
1753
1753
1754 def _stringmatcher(pattern):
1754 def _stringmatcher(pattern):
1755 """
1755 """
1756 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1756 accepts a string, possibly starting with 're:' or 'literal:' prefix.
1757 returns the matcher name, pattern, and matcher function.
1757 returns the matcher name, pattern, and matcher function.
1758 missing or unknown prefixes are treated as literal matches.
1758 missing or unknown prefixes are treated as literal matches.
1759
1759
1760 helper for tests:
1760 helper for tests:
1761 >>> def test(pattern, *tests):
1761 >>> def test(pattern, *tests):
1762 ... kind, pattern, matcher = _stringmatcher(pattern)
1762 ... kind, pattern, matcher = _stringmatcher(pattern)
1763 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1763 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
1764
1764
1765 exact matching (no prefix):
1765 exact matching (no prefix):
1766 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1766 >>> test('abcdefg', 'abc', 'def', 'abcdefg')
1767 ('literal', 'abcdefg', [False, False, True])
1767 ('literal', 'abcdefg', [False, False, True])
1768
1768
1769 regex matching ('re:' prefix)
1769 regex matching ('re:' prefix)
1770 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1770 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
1771 ('re', 'a.+b', [False, False, True])
1771 ('re', 'a.+b', [False, False, True])
1772
1772
1773 force exact matches ('literal:' prefix)
1773 force exact matches ('literal:' prefix)
1774 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1774 >>> test('literal:re:foobar', 'foobar', 're:foobar')
1775 ('literal', 're:foobar', [False, True])
1775 ('literal', 're:foobar', [False, True])
1776
1776
1777 unknown prefixes are ignored and treated as literals
1777 unknown prefixes are ignored and treated as literals
1778 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1778 >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
1779 ('literal', 'foo:bar', [False, False, True])
1779 ('literal', 'foo:bar', [False, False, True])
1780 """
1780 """
1781 if pattern.startswith('re:'):
1781 if pattern.startswith('re:'):
1782 pattern = pattern[3:]
1782 pattern = pattern[3:]
1783 try:
1783 try:
1784 regex = re.compile(pattern)
1784 regex = re.compile(pattern)
1785 except re.error, e:
1785 except re.error, e:
1786 raise error.ParseError(_('invalid regular expression: %s')
1786 raise error.ParseError(_('invalid regular expression: %s')
1787 % e)
1787 % e)
1788 return 're', pattern, regex.search
1788 return 're', pattern, regex.search
1789 elif pattern.startswith('literal:'):
1789 elif pattern.startswith('literal:'):
1790 pattern = pattern[8:]
1790 pattern = pattern[8:]
1791 return 'literal', pattern, pattern.__eq__
1791 return 'literal', pattern, pattern.__eq__
1792
1792
1793 def _substringmatcher(pattern):
1793 def _substringmatcher(pattern):
1794 kind, pattern, matcher = _stringmatcher(pattern)
1794 kind, pattern, matcher = _stringmatcher(pattern)
1795 if kind == 'literal':
1795 if kind == 'literal':
1796 matcher = lambda s: pattern in s
1796 matcher = lambda s: pattern in s
1797 return kind, pattern, matcher
1797 return kind, pattern, matcher
1798
1798
1799 def tag(repo, subset, x):
1799 def tag(repo, subset, x):
1800 """``tag([name])``
1800 """``tag([name])``
1801 The specified tag by name, or all tagged revisions if no name is given.
1801 The specified tag by name, or all tagged revisions if no name is given.
1802
1802
1803 If `name` starts with `re:`, the remainder of the name is treated as
1803 If `name` starts with `re:`, the remainder of the name is treated as
1804 a regular expression. To match a tag that actually starts with `re:`,
1804 a regular expression. To match a tag that actually starts with `re:`,
1805 use the prefix `literal:`.
1805 use the prefix `literal:`.
1806 """
1806 """
1807 # i18n: "tag" is a keyword
1807 # i18n: "tag" is a keyword
1808 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1808 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1809 cl = repo.changelog
1809 cl = repo.changelog
1810 if args:
1810 if args:
1811 pattern = getstring(args[0],
1811 pattern = getstring(args[0],
1812 # i18n: "tag" is a keyword
1812 # i18n: "tag" is a keyword
1813 _('the argument to tag must be a string'))
1813 _('the argument to tag must be a string'))
1814 kind, pattern, matcher = _stringmatcher(pattern)
1814 kind, pattern, matcher = _stringmatcher(pattern)
1815 if kind == 'literal':
1815 if kind == 'literal':
1816 # avoid resolving all tags
1816 # avoid resolving all tags
1817 tn = repo._tagscache.tags.get(pattern, None)
1817 tn = repo._tagscache.tags.get(pattern, None)
1818 if tn is None:
1818 if tn is None:
1819 raise util.Abort(_("tag '%s' does not exist") % pattern)
1819 raise util.Abort(_("tag '%s' does not exist") % pattern)
1820 s = set([repo[tn].rev()])
1820 s = set([repo[tn].rev()])
1821 else:
1821 else:
1822 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1822 s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
1823 else:
1823 else:
1824 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1824 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1825 return subset & s
1825 return subset & s
1826
1826
1827 def tagged(repo, subset, x):
1827 def tagged(repo, subset, x):
1828 return tag(repo, subset, x)
1828 return tag(repo, subset, x)
1829
1829
1830 def unstable(repo, subset, x):
1830 def unstable(repo, subset, x):
1831 """``unstable()``
1831 """``unstable()``
1832 Non-obsolete changesets with obsolete ancestors.
1832 Non-obsolete changesets with obsolete ancestors.
1833 """
1833 """
1834 # i18n: "unstable" is a keyword
1834 # i18n: "unstable" is a keyword
1835 getargs(x, 0, 0, _("unstable takes no arguments"))
1835 getargs(x, 0, 0, _("unstable takes no arguments"))
1836 unstables = obsmod.getrevs(repo, 'unstable')
1836 unstables = obsmod.getrevs(repo, 'unstable')
1837 return subset & unstables
1837 return subset & unstables
1838
1838
1839
1839
1840 def user(repo, subset, x):
1840 def user(repo, subset, x):
1841 """``user(string)``
1841 """``user(string)``
1842 User name contains string. The match is case-insensitive.
1842 User name contains string. The match is case-insensitive.
1843
1843
1844 If `string` starts with `re:`, the remainder of the string is treated as
1844 If `string` starts with `re:`, the remainder of the string is treated as
1845 a regular expression. To match a user that actually contains `re:`, use
1845 a regular expression. To match a user that actually contains `re:`, use
1846 the prefix `literal:`.
1846 the prefix `literal:`.
1847 """
1847 """
1848 return author(repo, subset, x)
1848 return author(repo, subset, x)
1849
1849
1850 # for internal use
1850 # for internal use
1851 def _list(repo, subset, x):
1851 def _list(repo, subset, x):
1852 s = getstring(x, "internal error")
1852 s = getstring(x, "internal error")
1853 if not s:
1853 if not s:
1854 return baseset()
1854 return baseset()
1855 ls = [repo[r].rev() for r in s.split('\0')]
1855 ls = [repo[r].rev() for r in s.split('\0')]
1856 s = subset
1856 s = subset
1857 return baseset([r for r in ls if r in s])
1857 return baseset([r for r in ls if r in s])
1858
1858
1859 # for internal use
1859 # for internal use
1860 def _intlist(repo, subset, x):
1860 def _intlist(repo, subset, x):
1861 s = getstring(x, "internal error")
1861 s = getstring(x, "internal error")
1862 if not s:
1862 if not s:
1863 return baseset()
1863 return baseset()
1864 ls = [int(r) for r in s.split('\0')]
1864 ls = [int(r) for r in s.split('\0')]
1865 s = subset
1865 s = subset
1866 return baseset([r for r in ls if r in s])
1866 return baseset([r for r in ls if r in s])
1867
1867
1868 # for internal use
1868 # for internal use
1869 def _hexlist(repo, subset, x):
1869 def _hexlist(repo, subset, x):
1870 s = getstring(x, "internal error")
1870 s = getstring(x, "internal error")
1871 if not s:
1871 if not s:
1872 return baseset()
1872 return baseset()
1873 cl = repo.changelog
1873 cl = repo.changelog
1874 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1874 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1875 s = subset
1875 s = subset
1876 return baseset([r for r in ls if r in s])
1876 return baseset([r for r in ls if r in s])
1877
1877
1878 symbols = {
1878 symbols = {
1879 "adds": adds,
1879 "adds": adds,
1880 "all": getall,
1880 "all": getall,
1881 "ancestor": ancestor,
1881 "ancestor": ancestor,
1882 "ancestors": ancestors,
1882 "ancestors": ancestors,
1883 "_firstancestors": _firstancestors,
1883 "_firstancestors": _firstancestors,
1884 "author": author,
1884 "author": author,
1885 "bisect": bisect,
1885 "bisect": bisect,
1886 "bisected": bisected,
1886 "bisected": bisected,
1887 "bookmark": bookmark,
1887 "bookmark": bookmark,
1888 "branch": branch,
1888 "branch": branch,
1889 "branchpoint": branchpoint,
1889 "branchpoint": branchpoint,
1890 "bumped": bumped,
1890 "bumped": bumped,
1891 "bundle": bundle,
1891 "bundle": bundle,
1892 "children": children,
1892 "children": children,
1893 "closed": closed,
1893 "closed": closed,
1894 "contains": contains,
1894 "contains": contains,
1895 "converted": converted,
1895 "converted": converted,
1896 "date": date,
1896 "date": date,
1897 "desc": desc,
1897 "desc": desc,
1898 "descendants": descendants,
1898 "descendants": descendants,
1899 "_firstdescendants": _firstdescendants,
1899 "_firstdescendants": _firstdescendants,
1900 "destination": destination,
1900 "destination": destination,
1901 "divergent": divergent,
1901 "divergent": divergent,
1902 "draft": draft,
1902 "draft": draft,
1903 "extinct": extinct,
1903 "extinct": extinct,
1904 "extra": extra,
1904 "extra": extra,
1905 "file": hasfile,
1905 "file": hasfile,
1906 "filelog": filelog,
1906 "filelog": filelog,
1907 "first": first,
1907 "first": first,
1908 "follow": follow,
1908 "follow": follow,
1909 "_followfirst": _followfirst,
1909 "_followfirst": _followfirst,
1910 "grep": grep,
1910 "grep": grep,
1911 "head": head,
1911 "head": head,
1912 "heads": heads,
1912 "heads": heads,
1913 "hidden": hidden,
1913 "hidden": hidden,
1914 "id": node_,
1914 "id": node_,
1915 "keyword": keyword,
1915 "keyword": keyword,
1916 "last": last,
1916 "last": last,
1917 "limit": limit,
1917 "limit": limit,
1918 "_matchfiles": _matchfiles,
1918 "_matchfiles": _matchfiles,
1919 "max": maxrev,
1919 "max": maxrev,
1920 "merge": merge,
1920 "merge": merge,
1921 "min": minrev,
1921 "min": minrev,
1922 "modifies": modifies,
1922 "modifies": modifies,
1923 "named": named,
1923 "named": named,
1924 "obsolete": obsolete,
1924 "obsolete": obsolete,
1925 "only": only,
1925 "only": only,
1926 "origin": origin,
1926 "origin": origin,
1927 "outgoing": outgoing,
1927 "outgoing": outgoing,
1928 "p1": p1,
1928 "p1": p1,
1929 "p2": p2,
1929 "p2": p2,
1930 "parents": parents,
1930 "parents": parents,
1931 "present": present,
1931 "present": present,
1932 "public": public,
1932 "public": public,
1933 "remote": remote,
1933 "remote": remote,
1934 "removes": removes,
1934 "removes": removes,
1935 "rev": rev,
1935 "rev": rev,
1936 "reverse": reverse,
1936 "reverse": reverse,
1937 "roots": roots,
1937 "roots": roots,
1938 "sort": sort,
1938 "sort": sort,
1939 "secret": secret,
1939 "secret": secret,
1940 "matching": matching,
1940 "matching": matching,
1941 "tag": tag,
1941 "tag": tag,
1942 "tagged": tagged,
1942 "tagged": tagged,
1943 "user": user,
1943 "user": user,
1944 "unstable": unstable,
1944 "unstable": unstable,
1945 "_list": _list,
1945 "_list": _list,
1946 "_intlist": _intlist,
1946 "_intlist": _intlist,
1947 "_hexlist": _hexlist,
1947 "_hexlist": _hexlist,
1948 }
1948 }
1949
1949
1950 # symbols which can't be used for a DoS attack for any given input
1950 # symbols which can't be used for a DoS attack for any given input
1951 # (e.g. those which accept regexes as plain strings shouldn't be included)
1951 # (e.g. those which accept regexes as plain strings shouldn't be included)
1952 # functions that just return a lot of changesets (like all) don't count here
1952 # functions that just return a lot of changesets (like all) don't count here
1953 safesymbols = set([
1953 safesymbols = set([
1954 "adds",
1954 "adds",
1955 "all",
1955 "all",
1956 "ancestor",
1956 "ancestor",
1957 "ancestors",
1957 "ancestors",
1958 "_firstancestors",
1958 "_firstancestors",
1959 "author",
1959 "author",
1960 "bisect",
1960 "bisect",
1961 "bisected",
1961 "bisected",
1962 "bookmark",
1962 "bookmark",
1963 "branch",
1963 "branch",
1964 "branchpoint",
1964 "branchpoint",
1965 "bumped",
1965 "bumped",
1966 "bundle",
1966 "bundle",
1967 "children",
1967 "children",
1968 "closed",
1968 "closed",
1969 "converted",
1969 "converted",
1970 "date",
1970 "date",
1971 "desc",
1971 "desc",
1972 "descendants",
1972 "descendants",
1973 "_firstdescendants",
1973 "_firstdescendants",
1974 "destination",
1974 "destination",
1975 "divergent",
1975 "divergent",
1976 "draft",
1976 "draft",
1977 "extinct",
1977 "extinct",
1978 "extra",
1978 "extra",
1979 "file",
1979 "file",
1980 "filelog",
1980 "filelog",
1981 "first",
1981 "first",
1982 "follow",
1982 "follow",
1983 "_followfirst",
1983 "_followfirst",
1984 "head",
1984 "head",
1985 "heads",
1985 "heads",
1986 "hidden",
1986 "hidden",
1987 "id",
1987 "id",
1988 "keyword",
1988 "keyword",
1989 "last",
1989 "last",
1990 "limit",
1990 "limit",
1991 "_matchfiles",
1991 "_matchfiles",
1992 "max",
1992 "max",
1993 "merge",
1993 "merge",
1994 "min",
1994 "min",
1995 "modifies",
1995 "modifies",
1996 "obsolete",
1996 "obsolete",
1997 "only",
1997 "only",
1998 "origin",
1998 "origin",
1999 "outgoing",
1999 "outgoing",
2000 "p1",
2000 "p1",
2001 "p2",
2001 "p2",
2002 "parents",
2002 "parents",
2003 "present",
2003 "present",
2004 "public",
2004 "public",
2005 "remote",
2005 "remote",
2006 "removes",
2006 "removes",
2007 "rev",
2007 "rev",
2008 "reverse",
2008 "reverse",
2009 "roots",
2009 "roots",
2010 "sort",
2010 "sort",
2011 "secret",
2011 "secret",
2012 "matching",
2012 "matching",
2013 "tag",
2013 "tag",
2014 "tagged",
2014 "tagged",
2015 "user",
2015 "user",
2016 "unstable",
2016 "unstable",
2017 "_list",
2017 "_list",
2018 "_intlist",
2018 "_intlist",
2019 "_hexlist",
2019 "_hexlist",
2020 ])
2020 ])
2021
2021
2022 methods = {
2022 methods = {
2023 "range": rangeset,
2023 "range": rangeset,
2024 "dagrange": dagrange,
2024 "dagrange": dagrange,
2025 "string": stringset,
2025 "string": stringset,
2026 "symbol": symbolset,
2026 "symbol": symbolset,
2027 "and": andset,
2027 "and": andset,
2028 "or": orset,
2028 "or": orset,
2029 "not": notset,
2029 "not": notset,
2030 "list": listset,
2030 "list": listset,
2031 "func": func,
2031 "func": func,
2032 "ancestor": ancestorspec,
2032 "ancestor": ancestorspec,
2033 "parent": parentspec,
2033 "parent": parentspec,
2034 "parentpost": p1,
2034 "parentpost": p1,
2035 "only": only,
2035 "only": only,
2036 "onlypost": only,
2036 "onlypost": only,
2037 }
2037 }
2038
2038
2039 def optimize(x, small):
2039 def optimize(x, small):
2040 if x is None:
2040 if x is None:
2041 return 0, x
2041 return 0, x
2042
2042
2043 smallbonus = 1
2043 smallbonus = 1
2044 if small:
2044 if small:
2045 smallbonus = .5
2045 smallbonus = .5
2046
2046
2047 op = x[0]
2047 op = x[0]
2048 if op == 'minus':
2048 if op == 'minus':
2049 return optimize(('and', x[1], ('not', x[2])), small)
2049 return optimize(('and', x[1], ('not', x[2])), small)
2050 elif op == 'only':
2050 elif op == 'only':
2051 return optimize(('func', ('symbol', 'only'),
2051 return optimize(('func', ('symbol', 'only'),
2052 ('list', x[1], x[2])), small)
2052 ('list', x[1], x[2])), small)
2053 elif op == 'dagrangepre':
2053 elif op == 'dagrangepre':
2054 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2054 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
2055 elif op == 'dagrangepost':
2055 elif op == 'dagrangepost':
2056 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2056 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
2057 elif op == 'rangepre':
2057 elif op == 'rangepre':
2058 return optimize(('range', ('string', '0'), x[1]), small)
2058 return optimize(('range', ('string', '0'), x[1]), small)
2059 elif op == 'rangepost':
2059 elif op == 'rangepost':
2060 return optimize(('range', x[1], ('string', 'tip')), small)
2060 return optimize(('range', x[1], ('string', 'tip')), small)
2061 elif op == 'negate':
2061 elif op == 'negate':
2062 return optimize(('string',
2062 return optimize(('string',
2063 '-' + getstring(x[1], _("can't negate that"))), small)
2063 '-' + getstring(x[1], _("can't negate that"))), small)
2064 elif op in 'string symbol negate':
2064 elif op in 'string symbol negate':
2065 return smallbonus, x # single revisions are small
2065 return smallbonus, x # single revisions are small
2066 elif op == 'and':
2066 elif op == 'and':
2067 wa, ta = optimize(x[1], True)
2067 wa, ta = optimize(x[1], True)
2068 wb, tb = optimize(x[2], True)
2068 wb, tb = optimize(x[2], True)
2069
2069
2070 # (::x and not ::y)/(not ::y and ::x) have a fast path
2070 # (::x and not ::y)/(not ::y and ::x) have a fast path
2071 def isonly(revs, bases):
2071 def isonly(revs, bases):
2072 return (
2072 return (
2073 revs[0] == 'func'
2073 revs[0] == 'func'
2074 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2074 and getstring(revs[1], _('not a symbol')) == 'ancestors'
2075 and bases[0] == 'not'
2075 and bases[0] == 'not'
2076 and bases[1][0] == 'func'
2076 and bases[1][0] == 'func'
2077 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2077 and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
2078
2078
2079 w = min(wa, wb)
2079 w = min(wa, wb)
2080 if isonly(ta, tb):
2080 if isonly(ta, tb):
2081 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2081 return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
2082 if isonly(tb, ta):
2082 if isonly(tb, ta):
2083 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2083 return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
2084
2084
2085 if wa > wb:
2085 if wa > wb:
2086 return w, (op, tb, ta)
2086 return w, (op, tb, ta)
2087 return w, (op, ta, tb)
2087 return w, (op, ta, tb)
2088 elif op == 'or':
2088 elif op == 'or':
2089 wa, ta = optimize(x[1], False)
2089 wa, ta = optimize(x[1], False)
2090 wb, tb = optimize(x[2], False)
2090 wb, tb = optimize(x[2], False)
2091 if wb < wa:
2091 if wb < wa:
2092 wb, wa = wa, wb
2092 wb, wa = wa, wb
2093 return max(wa, wb), (op, ta, tb)
2093 return max(wa, wb), (op, ta, tb)
2094 elif op == 'not':
2094 elif op == 'not':
2095 o = optimize(x[1], not small)
2095 o = optimize(x[1], not small)
2096 return o[0], (op, o[1])
2096 return o[0], (op, o[1])
2097 elif op == 'parentpost':
2097 elif op == 'parentpost':
2098 o = optimize(x[1], small)
2098 o = optimize(x[1], small)
2099 return o[0], (op, o[1])
2099 return o[0], (op, o[1])
2100 elif op == 'group':
2100 elif op == 'group':
2101 return optimize(x[1], small)
2101 return optimize(x[1], small)
2102 elif op in 'dagrange range list parent ancestorspec':
2102 elif op in 'dagrange range list parent ancestorspec':
2103 if op == 'parent':
2103 if op == 'parent':
2104 # x^:y means (x^) : y, not x ^ (:y)
2104 # x^:y means (x^) : y, not x ^ (:y)
2105 post = ('parentpost', x[1])
2105 post = ('parentpost', x[1])
2106 if x[2][0] == 'dagrangepre':
2106 if x[2][0] == 'dagrangepre':
2107 return optimize(('dagrange', post, x[2][1]), small)
2107 return optimize(('dagrange', post, x[2][1]), small)
2108 elif x[2][0] == 'rangepre':
2108 elif x[2][0] == 'rangepre':
2109 return optimize(('range', post, x[2][1]), small)
2109 return optimize(('range', post, x[2][1]), small)
2110
2110
2111 wa, ta = optimize(x[1], small)
2111 wa, ta = optimize(x[1], small)
2112 wb, tb = optimize(x[2], small)
2112 wb, tb = optimize(x[2], small)
2113 return wa + wb, (op, ta, tb)
2113 return wa + wb, (op, ta, tb)
2114 elif op == 'func':
2114 elif op == 'func':
2115 f = getstring(x[1], _("not a symbol"))
2115 f = getstring(x[1], _("not a symbol"))
2116 wa, ta = optimize(x[2], small)
2116 wa, ta = optimize(x[2], small)
2117 if f in ("author branch closed date desc file grep keyword "
2117 if f in ("author branch closed date desc file grep keyword "
2118 "outgoing user"):
2118 "outgoing user"):
2119 w = 10 # slow
2119 w = 10 # slow
2120 elif f in "modifies adds removes":
2120 elif f in "modifies adds removes":
2121 w = 30 # slower
2121 w = 30 # slower
2122 elif f == "contains":
2122 elif f == "contains":
2123 w = 100 # very slow
2123 w = 100 # very slow
2124 elif f == "ancestor":
2124 elif f == "ancestor":
2125 w = 1 * smallbonus
2125 w = 1 * smallbonus
2126 elif f in "reverse limit first _intlist":
2126 elif f in "reverse limit first _intlist":
2127 w = 0
2127 w = 0
2128 elif f in "sort":
2128 elif f in "sort":
2129 w = 10 # assume most sorts look at changelog
2129 w = 10 # assume most sorts look at changelog
2130 else:
2130 else:
2131 w = 1
2131 w = 1
2132 return w + wa, (op, x[1], ta)
2132 return w + wa, (op, x[1], ta)
2133 return 1, x
2133 return 1, x
2134
2134
2135 _aliasarg = ('func', ('symbol', '_aliasarg'))
2135 _aliasarg = ('func', ('symbol', '_aliasarg'))
2136 def _getaliasarg(tree):
2136 def _getaliasarg(tree):
2137 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2137 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
2138 return X, None otherwise.
2138 return X, None otherwise.
2139 """
2139 """
2140 if (len(tree) == 3 and tree[:2] == _aliasarg
2140 if (len(tree) == 3 and tree[:2] == _aliasarg
2141 and tree[2][0] == 'string'):
2141 and tree[2][0] == 'string'):
2142 return tree[2][1]
2142 return tree[2][1]
2143 return None
2143 return None
2144
2144
2145 def _checkaliasarg(tree, known=None):
2145 def _checkaliasarg(tree, known=None):
2146 """Check tree contains no _aliasarg construct or only ones which
2146 """Check tree contains no _aliasarg construct or only ones which
2147 value is in known. Used to avoid alias placeholders injection.
2147 value is in known. Used to avoid alias placeholders injection.
2148 """
2148 """
2149 if isinstance(tree, tuple):
2149 if isinstance(tree, tuple):
2150 arg = _getaliasarg(tree)
2150 arg = _getaliasarg(tree)
2151 if arg is not None and (not known or arg not in known):
2151 if arg is not None and (not known or arg not in known):
2152 raise error.ParseError(_("not a function: %s") % '_aliasarg')
2152 raise error.ParseError(_("not a function: %s") % '_aliasarg')
2153 for t in tree:
2153 for t in tree:
2154 _checkaliasarg(t, known)
2154 _checkaliasarg(t, known)
2155
2155
2156 # the set of valid characters for the initial letter of symbols in
2156 # the set of valid characters for the initial letter of symbols in
2157 # alias declarations and definitions
2157 # alias declarations and definitions
2158 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2158 _aliassyminitletters = set(c for c in [chr(i) for i in xrange(256)]
2159 if c.isalnum() or c in '._@$' or ord(c) > 127)
2159 if c.isalnum() or c in '._@$' or ord(c) > 127)
2160
2160
2161 def _tokenizealias(program, lookup=None):
2161 def _tokenizealias(program, lookup=None):
2162 """Parse alias declaration/definition into a stream of tokens
2162 """Parse alias declaration/definition into a stream of tokens
2163
2163
2164 This allows symbol names to use also ``$`` as an initial letter
2164 This allows symbol names to use also ``$`` as an initial letter
2165 (for backward compatibility), and callers of this function should
2165 (for backward compatibility), and callers of this function should
2166 examine whether ``$`` is used also for unexpected symbols or not.
2166 examine whether ``$`` is used also for unexpected symbols or not.
2167 """
2167 """
2168 return tokenize(program, lookup=lookup,
2168 return tokenize(program, lookup=lookup,
2169 syminitletters=_aliassyminitletters)
2169 syminitletters=_aliassyminitletters)
2170
2170
2171 def _parsealiasdecl(decl):
2171 def _parsealiasdecl(decl):
2172 """Parse alias declaration ``decl``
2172 """Parse alias declaration ``decl``
2173
2173
2174 This returns ``(name, tree, args, errorstr)`` tuple:
2174 This returns ``(name, tree, args, errorstr)`` tuple:
2175
2175
2176 - ``name``: of declared alias (may be ``decl`` itself at error)
2176 - ``name``: of declared alias (may be ``decl`` itself at error)
2177 - ``tree``: parse result (or ``None`` at error)
2177 - ``tree``: parse result (or ``None`` at error)
2178 - ``args``: list of alias argument names (or None for symbol declaration)
2178 - ``args``: list of alias argument names (or None for symbol declaration)
2179 - ``errorstr``: detail about detected error (or None)
2179 - ``errorstr``: detail about detected error (or None)
2180
2180
2181 >>> _parsealiasdecl('foo')
2181 >>> _parsealiasdecl('foo')
2182 ('foo', ('symbol', 'foo'), None, None)
2182 ('foo', ('symbol', 'foo'), None, None)
2183 >>> _parsealiasdecl('$foo')
2183 >>> _parsealiasdecl('$foo')
2184 ('$foo', None, None, "'$' not for alias arguments")
2184 ('$foo', None, None, "'$' not for alias arguments")
2185 >>> _parsealiasdecl('foo::bar')
2185 >>> _parsealiasdecl('foo::bar')
2186 ('foo::bar', None, None, 'invalid format')
2186 ('foo::bar', None, None, 'invalid format')
2187 >>> _parsealiasdecl('foo bar')
2187 >>> _parsealiasdecl('foo bar')
2188 ('foo bar', None, None, 'at 4: invalid token')
2188 ('foo bar', None, None, 'at 4: invalid token')
2189 >>> _parsealiasdecl('foo()')
2189 >>> _parsealiasdecl('foo()')
2190 ('foo', ('func', ('symbol', 'foo')), [], None)
2190 ('foo', ('func', ('symbol', 'foo')), [], None)
2191 >>> _parsealiasdecl('$foo()')
2191 >>> _parsealiasdecl('$foo()')
2192 ('$foo()', None, None, "'$' not for alias arguments")
2192 ('$foo()', None, None, "'$' not for alias arguments")
2193 >>> _parsealiasdecl('foo($1, $2)')
2193 >>> _parsealiasdecl('foo($1, $2)')
2194 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2194 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None)
2195 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2195 >>> _parsealiasdecl('foo(bar_bar, baz.baz)')
2196 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2196 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None)
2197 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2197 >>> _parsealiasdecl('foo($1, $2, nested($1, $2))')
2198 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2198 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list')
2199 >>> _parsealiasdecl('foo(bar($1, $2))')
2199 >>> _parsealiasdecl('foo(bar($1, $2))')
2200 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2200 ('foo(bar($1, $2))', None, None, 'invalid argument list')
2201 >>> _parsealiasdecl('foo("string")')
2201 >>> _parsealiasdecl('foo("string")')
2202 ('foo("string")', None, None, 'invalid argument list')
2202 ('foo("string")', None, None, 'invalid argument list')
2203 >>> _parsealiasdecl('foo($1, $2')
2203 >>> _parsealiasdecl('foo($1, $2')
2204 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2204 ('foo($1, $2', None, None, 'at 10: unexpected token: end')
2205 >>> _parsealiasdecl('foo("string')
2205 >>> _parsealiasdecl('foo("string')
2206 ('foo("string', None, None, 'at 5: unterminated string')
2206 ('foo("string', None, None, 'at 5: unterminated string')
2207 >>> _parsealiasdecl('foo($1, $2, $1)')
2207 >>> _parsealiasdecl('foo($1, $2, $1)')
2208 ('foo', None, None, 'argument names collide with each other')
2208 ('foo', None, None, 'argument names collide with each other')
2209 """
2209 """
2210 p = parser.parser(_tokenizealias, elements)
2210 p = parser.parser(_tokenizealias, elements)
2211 try:
2211 try:
2212 tree, pos = p.parse(decl)
2212 tree, pos = p.parse(decl)
2213 if (pos != len(decl)):
2213 if (pos != len(decl)):
2214 raise error.ParseError(_('invalid token'), pos)
2214 raise error.ParseError(_('invalid token'), pos)
2215
2215
2216 if isvalidsymbol(tree):
2216 if isvalidsymbol(tree):
2217 # "name = ...." style
2217 # "name = ...." style
2218 name = getsymbol(tree)
2218 name = getsymbol(tree)
2219 if name.startswith('$'):
2219 if name.startswith('$'):
2220 return (decl, None, None, _("'$' not for alias arguments"))
2220 return (decl, None, None, _("'$' not for alias arguments"))
2221 return (name, ('symbol', name), None, None)
2221 return (name, ('symbol', name), None, None)
2222
2222
2223 if isvalidfunc(tree):
2223 if isvalidfunc(tree):
2224 # "name(arg, ....) = ...." style
2224 # "name(arg, ....) = ...." style
2225 name = getfuncname(tree)
2225 name = getfuncname(tree)
2226 if name.startswith('$'):
2226 if name.startswith('$'):
2227 return (decl, None, None, _("'$' not for alias arguments"))
2227 return (decl, None, None, _("'$' not for alias arguments"))
2228 args = []
2228 args = []
2229 for arg in getfuncargs(tree):
2229 for arg in getfuncargs(tree):
2230 if not isvalidsymbol(arg):
2230 if not isvalidsymbol(arg):
2231 return (decl, None, None, _("invalid argument list"))
2231 return (decl, None, None, _("invalid argument list"))
2232 args.append(getsymbol(arg))
2232 args.append(getsymbol(arg))
2233 if len(args) != len(set(args)):
2233 if len(args) != len(set(args)):
2234 return (name, None, None,
2234 return (name, None, None,
2235 _("argument names collide with each other"))
2235 _("argument names collide with each other"))
2236 return (name, ('func', ('symbol', name)), args, None)
2236 return (name, ('func', ('symbol', name)), args, None)
2237
2237
2238 return (decl, None, None, _("invalid format"))
2238 return (decl, None, None, _("invalid format"))
2239 except error.ParseError, inst:
2239 except error.ParseError, inst:
2240 return (decl, None, None, parseerrordetail(inst))
2240 return (decl, None, None, parseerrordetail(inst))
2241
2241
2242 class revsetalias(object):
2242 class revsetalias(object):
2243 # whether own `error` information is already shown or not.
2243 # whether own `error` information is already shown or not.
2244 # this avoids showing same warning multiple times at each `findaliases`.
2244 # this avoids showing same warning multiple times at each `findaliases`.
2245 warned = False
2245 warned = False
2246
2246
2247 def __init__(self, name, value):
2247 def __init__(self, name, value):
2248 '''Aliases like:
2248 '''Aliases like:
2249
2249
2250 h = heads(default)
2250 h = heads(default)
2251 b($1) = ancestors($1) - ancestors(default)
2251 b($1) = ancestors($1) - ancestors(default)
2252 '''
2252 '''
2253 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2253 self.name, self.tree, self.args, self.error = _parsealiasdecl(name)
2254 if self.error:
2254 if self.error:
2255 self.error = _('failed to parse the declaration of revset alias'
2255 self.error = _('failed to parse the declaration of revset alias'
2256 ' "%s": %s') % (self.name, self.error)
2256 ' "%s": %s') % (self.name, self.error)
2257 return
2257 return
2258
2258
2259 if self.args:
2259 if self.args:
2260 for arg in self.args:
2260 for arg in self.args:
2261 # _aliasarg() is an unknown symbol only used separate
2261 # _aliasarg() is an unknown symbol only used separate
2262 # alias argument placeholders from regular strings.
2262 # alias argument placeholders from regular strings.
2263 value = value.replace(arg, '_aliasarg(%r)' % (arg,))
2263 value = value.replace(arg, '_aliasarg(%r)' % (arg,))
2264
2264
2265 try:
2265 try:
2266 self.replacement, pos = parse(value)
2266 self.replacement, pos = parse(value)
2267 if pos != len(value):
2267 if pos != len(value):
2268 raise error.ParseError(_('invalid token'), pos)
2268 raise error.ParseError(_('invalid token'), pos)
2269 # Check for placeholder injection
2269 # Check for placeholder injection
2270 _checkaliasarg(self.replacement, self.args)
2270 _checkaliasarg(self.replacement, self.args)
2271 except error.ParseError, inst:
2271 except error.ParseError, inst:
2272 self.error = _('failed to parse the definition of revset alias'
2272 self.error = _('failed to parse the definition of revset alias'
2273 ' "%s": %s') % (self.name, parseerrordetail(inst))
2273 ' "%s": %s') % (self.name, parseerrordetail(inst))
2274
2274
2275 def _getalias(aliases, tree):
2275 def _getalias(aliases, tree):
2276 """If tree looks like an unexpanded alias, return it. Return None
2276 """If tree looks like an unexpanded alias, return it. Return None
2277 otherwise.
2277 otherwise.
2278 """
2278 """
2279 if isinstance(tree, tuple) and tree:
2279 if isinstance(tree, tuple) and tree:
2280 if tree[0] == 'symbol' and len(tree) == 2:
2280 if tree[0] == 'symbol' and len(tree) == 2:
2281 name = tree[1]
2281 name = tree[1]
2282 alias = aliases.get(name)
2282 alias = aliases.get(name)
2283 if alias and alias.args is None and alias.tree == tree:
2283 if alias and alias.args is None and alias.tree == tree:
2284 return alias
2284 return alias
2285 if tree[0] == 'func' and len(tree) > 1:
2285 if tree[0] == 'func' and len(tree) > 1:
2286 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2286 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
2287 name = tree[1][1]
2287 name = tree[1][1]
2288 alias = aliases.get(name)
2288 alias = aliases.get(name)
2289 if alias and alias.args is not None and alias.tree == tree[:2]:
2289 if alias and alias.args is not None and alias.tree == tree[:2]:
2290 return alias
2290 return alias
2291 return None
2291 return None
2292
2292
2293 def _expandargs(tree, args):
2293 def _expandargs(tree, args):
2294 """Replace _aliasarg instances with the substitution value of the
2294 """Replace _aliasarg instances with the substitution value of the
2295 same name in args, recursively.
2295 same name in args, recursively.
2296 """
2296 """
2297 if not tree or not isinstance(tree, tuple):
2297 if not tree or not isinstance(tree, tuple):
2298 return tree
2298 return tree
2299 arg = _getaliasarg(tree)
2299 arg = _getaliasarg(tree)
2300 if arg is not None:
2300 if arg is not None:
2301 return args[arg]
2301 return args[arg]
2302 return tuple(_expandargs(t, args) for t in tree)
2302 return tuple(_expandargs(t, args) for t in tree)
2303
2303
2304 def _expandaliases(aliases, tree, expanding, cache):
2304 def _expandaliases(aliases, tree, expanding, cache):
2305 """Expand aliases in tree, recursively.
2305 """Expand aliases in tree, recursively.
2306
2306
2307 'aliases' is a dictionary mapping user defined aliases to
2307 'aliases' is a dictionary mapping user defined aliases to
2308 revsetalias objects.
2308 revsetalias objects.
2309 """
2309 """
2310 if not isinstance(tree, tuple):
2310 if not isinstance(tree, tuple):
2311 # Do not expand raw strings
2311 # Do not expand raw strings
2312 return tree
2312 return tree
2313 alias = _getalias(aliases, tree)
2313 alias = _getalias(aliases, tree)
2314 if alias is not None:
2314 if alias is not None:
2315 if alias.error:
2315 if alias.error:
2316 raise util.Abort(alias.error)
2316 raise util.Abort(alias.error)
2317 if alias in expanding:
2317 if alias in expanding:
2318 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2318 raise error.ParseError(_('infinite expansion of revset alias "%s" '
2319 'detected') % alias.name)
2319 'detected') % alias.name)
2320 expanding.append(alias)
2320 expanding.append(alias)
2321 if alias.name not in cache:
2321 if alias.name not in cache:
2322 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2322 cache[alias.name] = _expandaliases(aliases, alias.replacement,
2323 expanding, cache)
2323 expanding, cache)
2324 result = cache[alias.name]
2324 result = cache[alias.name]
2325 expanding.pop()
2325 expanding.pop()
2326 if alias.args is not None:
2326 if alias.args is not None:
2327 l = getlist(tree[2])
2327 l = getlist(tree[2])
2328 if len(l) != len(alias.args):
2328 if len(l) != len(alias.args):
2329 raise error.ParseError(
2329 raise error.ParseError(
2330 _('invalid number of arguments: %s') % len(l))
2330 _('invalid number of arguments: %s') % len(l))
2331 l = [_expandaliases(aliases, a, [], cache) for a in l]
2331 l = [_expandaliases(aliases, a, [], cache) for a in l]
2332 result = _expandargs(result, dict(zip(alias.args, l)))
2332 result = _expandargs(result, dict(zip(alias.args, l)))
2333 else:
2333 else:
2334 result = tuple(_expandaliases(aliases, t, expanding, cache)
2334 result = tuple(_expandaliases(aliases, t, expanding, cache)
2335 for t in tree)
2335 for t in tree)
2336 return result
2336 return result
2337
2337
2338 def findaliases(ui, tree, showwarning=None):
2338 def findaliases(ui, tree, showwarning=None):
2339 _checkaliasarg(tree)
2339 _checkaliasarg(tree)
2340 aliases = {}
2340 aliases = {}
2341 for k, v in ui.configitems('revsetalias'):
2341 for k, v in ui.configitems('revsetalias'):
2342 alias = revsetalias(k, v)
2342 alias = revsetalias(k, v)
2343 aliases[alias.name] = alias
2343 aliases[alias.name] = alias
2344 tree = _expandaliases(aliases, tree, [], {})
2344 tree = _expandaliases(aliases, tree, [], {})
2345 if showwarning:
2345 if showwarning:
2346 # warn about problematic (but not referred) aliases
2346 # warn about problematic (but not referred) aliases
2347 for name, alias in sorted(aliases.iteritems()):
2347 for name, alias in sorted(aliases.iteritems()):
2348 if alias.error and not alias.warned:
2348 if alias.error and not alias.warned:
2349 showwarning(_('warning: %s\n') % (alias.error))
2349 showwarning(_('warning: %s\n') % (alias.error))
2350 alias.warned = True
2350 alias.warned = True
2351 return tree
2351 return tree
2352
2352
2353 def foldconcat(tree):
2353 def foldconcat(tree):
2354 """Fold elements to be concatenated by `##`
2354 """Fold elements to be concatenated by `##`
2355 """
2355 """
2356 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2356 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2357 return tree
2357 return tree
2358 if tree[0] == '_concat':
2358 if tree[0] == '_concat':
2359 pending = [tree]
2359 pending = [tree]
2360 l = []
2360 l = []
2361 while pending:
2361 while pending:
2362 e = pending.pop()
2362 e = pending.pop()
2363 if e[0] == '_concat':
2363 if e[0] == '_concat':
2364 pending.extend(reversed(e[1:]))
2364 pending.extend(reversed(e[1:]))
2365 elif e[0] in ('string', 'symbol'):
2365 elif e[0] in ('string', 'symbol'):
2366 l.append(e[1])
2366 l.append(e[1])
2367 else:
2367 else:
2368 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2368 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
2369 raise error.ParseError(msg)
2369 raise error.ParseError(msg)
2370 return ('string', ''.join(l))
2370 return ('string', ''.join(l))
2371 else:
2371 else:
2372 return tuple(foldconcat(t) for t in tree)
2372 return tuple(foldconcat(t) for t in tree)
2373
2373
2374 def parse(spec, lookup=None):
2374 def parse(spec, lookup=None):
2375 p = parser.parser(tokenize, elements)
2375 p = parser.parser(tokenize, elements)
2376 return p.parse(spec, lookup=lookup)
2376 return p.parse(spec, lookup=lookup)
2377
2377
2378 def match(ui, spec, repo=None):
2378 def match(ui, spec, repo=None):
2379 if not spec:
2379 if not spec:
2380 raise error.ParseError(_("empty query"))
2380 raise error.ParseError(_("empty query"))
2381 lookup = None
2381 lookup = None
2382 if repo:
2382 if repo:
2383 lookup = repo.__contains__
2383 lookup = repo.__contains__
2384 tree, pos = parse(spec, lookup)
2384 tree, pos = parse(spec, lookup)
2385 if (pos != len(spec)):
2385 if (pos != len(spec)):
2386 raise error.ParseError(_("invalid token"), pos)
2386 raise error.ParseError(_("invalid token"), pos)
2387 if ui:
2387 if ui:
2388 tree = findaliases(ui, tree, showwarning=ui.warn)
2388 tree = findaliases(ui, tree, showwarning=ui.warn)
2389 tree = foldconcat(tree)
2389 tree = foldconcat(tree)
2390 weight, tree = optimize(tree, True)
2390 weight, tree = optimize(tree, True)
2391 def mfunc(repo, subset):
2391 def mfunc(repo, subset):
2392 if util.safehasattr(subset, 'isascending'):
2392 if util.safehasattr(subset, 'isascending'):
2393 result = getset(repo, subset, tree)
2393 result = getset(repo, subset, tree)
2394 else:
2394 else:
2395 result = getset(repo, baseset(subset), tree)
2395 result = getset(repo, baseset(subset), tree)
2396 return result
2396 return result
2397 return mfunc
2397 return mfunc
2398
2398
2399 def formatspec(expr, *args):
2399 def formatspec(expr, *args):
2400 '''
2400 '''
2401 This is a convenience function for using revsets internally, and
2401 This is a convenience function for using revsets internally, and
2402 escapes arguments appropriately. Aliases are intentionally ignored
2402 escapes arguments appropriately. Aliases are intentionally ignored
2403 so that intended expression behavior isn't accidentally subverted.
2403 so that intended expression behavior isn't accidentally subverted.
2404
2404
2405 Supported arguments:
2405 Supported arguments:
2406
2406
2407 %r = revset expression, parenthesized
2407 %r = revset expression, parenthesized
2408 %d = int(arg), no quoting
2408 %d = int(arg), no quoting
2409 %s = string(arg), escaped and single-quoted
2409 %s = string(arg), escaped and single-quoted
2410 %b = arg.branch(), escaped and single-quoted
2410 %b = arg.branch(), escaped and single-quoted
2411 %n = hex(arg), single-quoted
2411 %n = hex(arg), single-quoted
2412 %% = a literal '%'
2412 %% = a literal '%'
2413
2413
2414 Prefixing the type with 'l' specifies a parenthesized list of that type.
2414 Prefixing the type with 'l' specifies a parenthesized list of that type.
2415
2415
2416 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2416 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
2417 '(10 or 11):: and ((this()) or (that()))'
2417 '(10 or 11):: and ((this()) or (that()))'
2418 >>> formatspec('%d:: and not %d::', 10, 20)
2418 >>> formatspec('%d:: and not %d::', 10, 20)
2419 '10:: and not 20::'
2419 '10:: and not 20::'
2420 >>> formatspec('%ld or %ld', [], [1])
2420 >>> formatspec('%ld or %ld', [], [1])
2421 "_list('') or 1"
2421 "_list('') or 1"
2422 >>> formatspec('keyword(%s)', 'foo\\xe9')
2422 >>> formatspec('keyword(%s)', 'foo\\xe9')
2423 "keyword('foo\\\\xe9')"
2423 "keyword('foo\\\\xe9')"
2424 >>> b = lambda: 'default'
2424 >>> b = lambda: 'default'
2425 >>> b.branch = b
2425 >>> b.branch = b
2426 >>> formatspec('branch(%b)', b)
2426 >>> formatspec('branch(%b)', b)
2427 "branch('default')"
2427 "branch('default')"
2428 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2428 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
2429 "root(_list('a\\x00b\\x00c\\x00d'))"
2429 "root(_list('a\\x00b\\x00c\\x00d'))"
2430 '''
2430 '''
2431
2431
2432 def quote(s):
2432 def quote(s):
2433 return repr(str(s))
2433 return repr(str(s))
2434
2434
2435 def argtype(c, arg):
2435 def argtype(c, arg):
2436 if c == 'd':
2436 if c == 'd':
2437 return str(int(arg))
2437 return str(int(arg))
2438 elif c == 's':
2438 elif c == 's':
2439 return quote(arg)
2439 return quote(arg)
2440 elif c == 'r':
2440 elif c == 'r':
2441 parse(arg) # make sure syntax errors are confined
2441 parse(arg) # make sure syntax errors are confined
2442 return '(%s)' % arg
2442 return '(%s)' % arg
2443 elif c == 'n':
2443 elif c == 'n':
2444 return quote(node.hex(arg))
2444 return quote(node.hex(arg))
2445 elif c == 'b':
2445 elif c == 'b':
2446 return quote(arg.branch())
2446 return quote(arg.branch())
2447
2447
2448 def listexp(s, t):
2448 def listexp(s, t):
2449 l = len(s)
2449 l = len(s)
2450 if l == 0:
2450 if l == 0:
2451 return "_list('')"
2451 return "_list('')"
2452 elif l == 1:
2452 elif l == 1:
2453 return argtype(t, s[0])
2453 return argtype(t, s[0])
2454 elif t == 'd':
2454 elif t == 'd':
2455 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2455 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
2456 elif t == 's':
2456 elif t == 's':
2457 return "_list('%s')" % "\0".join(s)
2457 return "_list('%s')" % "\0".join(s)
2458 elif t == 'n':
2458 elif t == 'n':
2459 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2459 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
2460 elif t == 'b':
2460 elif t == 'b':
2461 return "_list('%s')" % "\0".join(a.branch() for a in s)
2461 return "_list('%s')" % "\0".join(a.branch() for a in s)
2462
2462
2463 m = l // 2
2463 m = l // 2
2464 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2464 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
2465
2465
2466 ret = ''
2466 ret = ''
2467 pos = 0
2467 pos = 0
2468 arg = 0
2468 arg = 0
2469 while pos < len(expr):
2469 while pos < len(expr):
2470 c = expr[pos]
2470 c = expr[pos]
2471 if c == '%':
2471 if c == '%':
2472 pos += 1
2472 pos += 1
2473 d = expr[pos]
2473 d = expr[pos]
2474 if d == '%':
2474 if d == '%':
2475 ret += d
2475 ret += d
2476 elif d in 'dsnbr':
2476 elif d in 'dsnbr':
2477 ret += argtype(d, args[arg])
2477 ret += argtype(d, args[arg])
2478 arg += 1
2478 arg += 1
2479 elif d == 'l':
2479 elif d == 'l':
2480 # a list of some type
2480 # a list of some type
2481 pos += 1
2481 pos += 1
2482 d = expr[pos]
2482 d = expr[pos]
2483 ret += listexp(list(args[arg]), d)
2483 ret += listexp(list(args[arg]), d)
2484 arg += 1
2484 arg += 1
2485 else:
2485 else:
2486 raise util.Abort('unexpected revspec format character %s' % d)
2486 raise util.Abort('unexpected revspec format character %s' % d)
2487 else:
2487 else:
2488 ret += c
2488 ret += c
2489 pos += 1
2489 pos += 1
2490
2490
2491 return ret
2491 return ret
2492
2492
2493 def prettyformat(tree):
2493 def prettyformat(tree):
2494 def _prettyformat(tree, level, lines):
2494 def _prettyformat(tree, level, lines):
2495 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2495 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2496 lines.append((level, str(tree)))
2496 lines.append((level, str(tree)))
2497 else:
2497 else:
2498 lines.append((level, '(%s' % tree[0]))
2498 lines.append((level, '(%s' % tree[0]))
2499 for s in tree[1:]:
2499 for s in tree[1:]:
2500 _prettyformat(s, level + 1, lines)
2500 _prettyformat(s, level + 1, lines)
2501 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
2501 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
2502
2502
2503 lines = []
2503 lines = []
2504 _prettyformat(tree, 0, lines)
2504 _prettyformat(tree, 0, lines)
2505 output = '\n'.join((' '*l + s) for l, s in lines)
2505 output = '\n'.join((' '*l + s) for l, s in lines)
2506 return output
2506 return output
2507
2507
2508 def depth(tree):
2508 def depth(tree):
2509 if isinstance(tree, tuple):
2509 if isinstance(tree, tuple):
2510 return max(map(depth, tree)) + 1
2510 return max(map(depth, tree)) + 1
2511 else:
2511 else:
2512 return 0
2512 return 0
2513
2513
2514 def funcsused(tree):
2514 def funcsused(tree):
2515 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2515 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
2516 return set()
2516 return set()
2517 else:
2517 else:
2518 funcs = set()
2518 funcs = set()
2519 for s in tree[1:]:
2519 for s in tree[1:]:
2520 funcs |= funcsused(s)
2520 funcs |= funcsused(s)
2521 if tree[0] == 'func':
2521 if tree[0] == 'func':
2522 funcs.add(tree[1][1])
2522 funcs.add(tree[1][1])
2523 return funcs
2523 return funcs
2524
2524
2525 class abstractsmartset(object):
2525 class abstractsmartset(object):
2526
2526
2527 def __nonzero__(self):
2527 def __nonzero__(self):
2528 """True if the smartset is not empty"""
2528 """True if the smartset is not empty"""
2529 raise NotImplementedError()
2529 raise NotImplementedError()
2530
2530
2531 def __contains__(self, rev):
2531 def __contains__(self, rev):
2532 """provide fast membership testing"""
2532 """provide fast membership testing"""
2533 raise NotImplementedError()
2533 raise NotImplementedError()
2534
2534
2535 def __iter__(self):
2535 def __iter__(self):
2536 """iterate the set in the order it is supposed to be iterated"""
2536 """iterate the set in the order it is supposed to be iterated"""
2537 raise NotImplementedError()
2537 raise NotImplementedError()
2538
2538
2539 # Attributes containing a function to perform a fast iteration in a given
2539 # Attributes containing a function to perform a fast iteration in a given
2540 # direction. A smartset can have none, one, or both defined.
2540 # direction. A smartset can have none, one, or both defined.
2541 #
2541 #
2542 # Default value is None instead of a function returning None to avoid
2542 # Default value is None instead of a function returning None to avoid
2543 # initializing an iterator just for testing if a fast method exists.
2543 # initializing an iterator just for testing if a fast method exists.
2544 fastasc = None
2544 fastasc = None
2545 fastdesc = None
2545 fastdesc = None
2546
2546
2547 def isascending(self):
2547 def isascending(self):
2548 """True if the set will iterate in ascending order"""
2548 """True if the set will iterate in ascending order"""
2549 raise NotImplementedError()
2549 raise NotImplementedError()
2550
2550
2551 def isdescending(self):
2551 def isdescending(self):
2552 """True if the set will iterate in descending order"""
2552 """True if the set will iterate in descending order"""
2553 raise NotImplementedError()
2553 raise NotImplementedError()
2554
2554
2555 def min(self):
2555 def min(self):
2556 """return the minimum element in the set"""
2556 """return the minimum element in the set"""
2557 if self.fastasc is not None:
2557 if self.fastasc is not None:
2558 for r in self.fastasc():
2558 for r in self.fastasc():
2559 return r
2559 return r
2560 raise ValueError('arg is an empty sequence')
2560 raise ValueError('arg is an empty sequence')
2561 return min(self)
2561 return min(self)
2562
2562
2563 def max(self):
2563 def max(self):
2564 """return the maximum element in the set"""
2564 """return the maximum element in the set"""
2565 if self.fastdesc is not None:
2565 if self.fastdesc is not None:
2566 for r in self.fastdesc():
2566 for r in self.fastdesc():
2567 return r
2567 return r
2568 raise ValueError('arg is an empty sequence')
2568 raise ValueError('arg is an empty sequence')
2569 return max(self)
2569 return max(self)
2570
2570
2571 def first(self):
2571 def first(self):
2572 """return the first element in the set (user iteration perspective)
2572 """return the first element in the set (user iteration perspective)
2573
2573
2574 Return None if the set is empty"""
2574 Return None if the set is empty"""
2575 raise NotImplementedError()
2575 raise NotImplementedError()
2576
2576
2577 def last(self):
2577 def last(self):
2578 """return the last element in the set (user iteration perspective)
2578 """return the last element in the set (user iteration perspective)
2579
2579
2580 Return None if the set is empty"""
2580 Return None if the set is empty"""
2581 raise NotImplementedError()
2581 raise NotImplementedError()
2582
2582
2583 def __len__(self):
2583 def __len__(self):
2584 """return the length of the smartsets
2584 """return the length of the smartsets
2585
2585
2586 This can be expensive on smartset that could be lazy otherwise."""
2586 This can be expensive on smartset that could be lazy otherwise."""
2587 raise NotImplementedError()
2587 raise NotImplementedError()
2588
2588
2589 def reverse(self):
2589 def reverse(self):
2590 """reverse the expected iteration order"""
2590 """reverse the expected iteration order"""
2591 raise NotImplementedError()
2591 raise NotImplementedError()
2592
2592
2593 def sort(self, reverse=True):
2593 def sort(self, reverse=True):
2594 """get the set to iterate in an ascending or descending order"""
2594 """get the set to iterate in an ascending or descending order"""
2595 raise NotImplementedError()
2595 raise NotImplementedError()
2596
2596
2597 def __and__(self, other):
2597 def __and__(self, other):
2598 """Returns a new object with the intersection of the two collections.
2598 """Returns a new object with the intersection of the two collections.
2599
2599
2600 This is part of the mandatory API for smartset."""
2600 This is part of the mandatory API for smartset."""
2601 return self.filter(other.__contains__, cache=False)
2601 return self.filter(other.__contains__, cache=False)
2602
2602
2603 def __add__(self, other):
2603 def __add__(self, other):
2604 """Returns a new object with the union of the two collections.
2604 """Returns a new object with the union of the two collections.
2605
2605
2606 This is part of the mandatory API for smartset."""
2606 This is part of the mandatory API for smartset."""
2607 return addset(self, other)
2607 return addset(self, other)
2608
2608
2609 def __sub__(self, other):
2609 def __sub__(self, other):
2610 """Returns a new object with the substraction of the two collections.
2610 """Returns a new object with the substraction of the two collections.
2611
2611
2612 This is part of the mandatory API for smartset."""
2612 This is part of the mandatory API for smartset."""
2613 c = other.__contains__
2613 c = other.__contains__
2614 return self.filter(lambda r: not c(r), cache=False)
2614 return self.filter(lambda r: not c(r), cache=False)
2615
2615
2616 def filter(self, condition, cache=True):
2616 def filter(self, condition, cache=True):
2617 """Returns this smartset filtered by condition as a new smartset.
2617 """Returns this smartset filtered by condition as a new smartset.
2618
2618
2619 `condition` is a callable which takes a revision number and returns a
2619 `condition` is a callable which takes a revision number and returns a
2620 boolean.
2620 boolean.
2621
2621
2622 This is part of the mandatory API for smartset."""
2622 This is part of the mandatory API for smartset."""
2623 # builtin cannot be cached. but do not needs to
2623 # builtin cannot be cached. but do not needs to
2624 if cache and util.safehasattr(condition, 'func_code'):
2624 if cache and util.safehasattr(condition, 'func_code'):
2625 condition = util.cachefunc(condition)
2625 condition = util.cachefunc(condition)
2626 return filteredset(self, condition)
2626 return filteredset(self, condition)
2627
2627
2628 class baseset(abstractsmartset):
2628 class baseset(abstractsmartset):
2629 """Basic data structure that represents a revset and contains the basic
2629 """Basic data structure that represents a revset and contains the basic
2630 operation that it should be able to perform.
2630 operation that it should be able to perform.
2631
2631
2632 Every method in this class should be implemented by any smartset class.
2632 Every method in this class should be implemented by any smartset class.
2633 """
2633 """
2634 def __init__(self, data=()):
2634 def __init__(self, data=()):
2635 if not isinstance(data, list):
2635 if not isinstance(data, list):
2636 data = list(data)
2636 data = list(data)
2637 self._list = data
2637 self._list = data
2638 self._ascending = None
2638 self._ascending = None
2639
2639
2640 @util.propertycache
2640 @util.propertycache
2641 def _set(self):
2641 def _set(self):
2642 return set(self._list)
2642 return set(self._list)
2643
2643
2644 @util.propertycache
2644 @util.propertycache
2645 def _asclist(self):
2645 def _asclist(self):
2646 asclist = self._list[:]
2646 asclist = self._list[:]
2647 asclist.sort()
2647 asclist.sort()
2648 return asclist
2648 return asclist
2649
2649
2650 def __iter__(self):
2650 def __iter__(self):
2651 if self._ascending is None:
2651 if self._ascending is None:
2652 return iter(self._list)
2652 return iter(self._list)
2653 elif self._ascending:
2653 elif self._ascending:
2654 return iter(self._asclist)
2654 return iter(self._asclist)
2655 else:
2655 else:
2656 return reversed(self._asclist)
2656 return reversed(self._asclist)
2657
2657
2658 def fastasc(self):
2658 def fastasc(self):
2659 return iter(self._asclist)
2659 return iter(self._asclist)
2660
2660
2661 def fastdesc(self):
2661 def fastdesc(self):
2662 return reversed(self._asclist)
2662 return reversed(self._asclist)
2663
2663
2664 @util.propertycache
2664 @util.propertycache
2665 def __contains__(self):
2665 def __contains__(self):
2666 return self._set.__contains__
2666 return self._set.__contains__
2667
2667
2668 def __nonzero__(self):
2668 def __nonzero__(self):
2669 return bool(self._list)
2669 return bool(self._list)
2670
2670
2671 def sort(self, reverse=False):
2671 def sort(self, reverse=False):
2672 self._ascending = not bool(reverse)
2672 self._ascending = not bool(reverse)
2673
2673
2674 def reverse(self):
2674 def reverse(self):
2675 if self._ascending is None:
2675 if self._ascending is None:
2676 self._list.reverse()
2676 self._list.reverse()
2677 else:
2677 else:
2678 self._ascending = not self._ascending
2678 self._ascending = not self._ascending
2679
2679
2680 def __len__(self):
2680 def __len__(self):
2681 return len(self._list)
2681 return len(self._list)
2682
2682
2683 def isascending(self):
2683 def isascending(self):
2684 """Returns True if the collection is ascending order, False if not.
2684 """Returns True if the collection is ascending order, False if not.
2685
2685
2686 This is part of the mandatory API for smartset."""
2686 This is part of the mandatory API for smartset."""
2687 if len(self) <= 1:
2687 if len(self) <= 1:
2688 return True
2688 return True
2689 return self._ascending is not None and self._ascending
2689 return self._ascending is not None and self._ascending
2690
2690
2691 def isdescending(self):
2691 def isdescending(self):
2692 """Returns True if the collection is descending order, False if not.
2692 """Returns True if the collection is descending order, False if not.
2693
2693
2694 This is part of the mandatory API for smartset."""
2694 This is part of the mandatory API for smartset."""
2695 if len(self) <= 1:
2695 if len(self) <= 1:
2696 return True
2696 return True
2697 return self._ascending is not None and not self._ascending
2697 return self._ascending is not None and not self._ascending
2698
2698
2699 def first(self):
2699 def first(self):
2700 if self:
2700 if self:
2701 if self._ascending is None:
2701 if self._ascending is None:
2702 return self._list[0]
2702 return self._list[0]
2703 elif self._ascending:
2703 elif self._ascending:
2704 return self._asclist[0]
2704 return self._asclist[0]
2705 else:
2705 else:
2706 return self._asclist[-1]
2706 return self._asclist[-1]
2707 return None
2707 return None
2708
2708
2709 def last(self):
2709 def last(self):
2710 if self:
2710 if self:
2711 if self._ascending is None:
2711 if self._ascending is None:
2712 return self._list[-1]
2712 return self._list[-1]
2713 elif self._ascending:
2713 elif self._ascending:
2714 return self._asclist[-1]
2714 return self._asclist[-1]
2715 else:
2715 else:
2716 return self._asclist[0]
2716 return self._asclist[0]
2717 return None
2717 return None
2718
2718
2719 class filteredset(abstractsmartset):
2719 class filteredset(abstractsmartset):
2720 """Duck type for baseset class which iterates lazily over the revisions in
2720 """Duck type for baseset class which iterates lazily over the revisions in
2721 the subset and contains a function which tests for membership in the
2721 the subset and contains a function which tests for membership in the
2722 revset
2722 revset
2723 """
2723 """
2724 def __init__(self, subset, condition=lambda x: True):
2724 def __init__(self, subset, condition=lambda x: True):
2725 """
2725 """
2726 condition: a function that decide whether a revision in the subset
2726 condition: a function that decide whether a revision in the subset
2727 belongs to the revset or not.
2727 belongs to the revset or not.
2728 """
2728 """
2729 self._subset = subset
2729 self._subset = subset
2730 self._condition = condition
2730 self._condition = condition
2731 self._cache = {}
2731 self._cache = {}
2732
2732
2733 def __contains__(self, x):
2733 def __contains__(self, x):
2734 c = self._cache
2734 c = self._cache
2735 if x not in c:
2735 if x not in c:
2736 v = c[x] = x in self._subset and self._condition(x)
2736 v = c[x] = x in self._subset and self._condition(x)
2737 return v
2737 return v
2738 return c[x]
2738 return c[x]
2739
2739
2740 def __iter__(self):
2740 def __iter__(self):
2741 return self._iterfilter(self._subset)
2741 return self._iterfilter(self._subset)
2742
2742
2743 def _iterfilter(self, it):
2743 def _iterfilter(self, it):
2744 cond = self._condition
2744 cond = self._condition
2745 for x in it:
2745 for x in it:
2746 if cond(x):
2746 if cond(x):
2747 yield x
2747 yield x
2748
2748
2749 @property
2749 @property
2750 def fastasc(self):
2750 def fastasc(self):
2751 it = self._subset.fastasc
2751 it = self._subset.fastasc
2752 if it is None:
2752 if it is None:
2753 return None
2753 return None
2754 return lambda: self._iterfilter(it())
2754 return lambda: self._iterfilter(it())
2755
2755
2756 @property
2756 @property
2757 def fastdesc(self):
2757 def fastdesc(self):
2758 it = self._subset.fastdesc
2758 it = self._subset.fastdesc
2759 if it is None:
2759 if it is None:
2760 return None
2760 return None
2761 return lambda: self._iterfilter(it())
2761 return lambda: self._iterfilter(it())
2762
2762
2763 def __nonzero__(self):
2763 def __nonzero__(self):
2764 for r in self:
2764 for r in self:
2765 return True
2765 return True
2766 return False
2766 return False
2767
2767
2768 def __len__(self):
2768 def __len__(self):
2769 # Basic implementation to be changed in future patches.
2769 # Basic implementation to be changed in future patches.
2770 l = baseset([r for r in self])
2770 l = baseset([r for r in self])
2771 return len(l)
2771 return len(l)
2772
2772
2773 def sort(self, reverse=False):
2773 def sort(self, reverse=False):
2774 self._subset.sort(reverse=reverse)
2774 self._subset.sort(reverse=reverse)
2775
2775
2776 def reverse(self):
2776 def reverse(self):
2777 self._subset.reverse()
2777 self._subset.reverse()
2778
2778
2779 def isascending(self):
2779 def isascending(self):
2780 return self._subset.isascending()
2780 return self._subset.isascending()
2781
2781
2782 def isdescending(self):
2782 def isdescending(self):
2783 return self._subset.isdescending()
2783 return self._subset.isdescending()
2784
2784
2785 def first(self):
2785 def first(self):
2786 for x in self:
2786 for x in self:
2787 return x
2787 return x
2788 return None
2788 return None
2789
2789
2790 def last(self):
2790 def last(self):
2791 it = None
2791 it = None
2792 if self._subset.isascending:
2792 if self._subset.isascending:
2793 it = self.fastdesc
2793 it = self.fastdesc
2794 elif self._subset.isdescending:
2794 elif self._subset.isdescending:
2795 it = self.fastdesc
2795 it = self.fastdesc
2796 if it is None:
2796 if it is None:
2797 # slowly consume everything. This needs improvement
2797 # slowly consume everything. This needs improvement
2798 it = lambda: reversed(list(self))
2798 it = lambda: reversed(list(self))
2799 for x in it():
2799 for x in it():
2800 return x
2800 return x
2801 return None
2801 return None
2802
2802
2803 class addset(abstractsmartset):
2803 class addset(abstractsmartset):
2804 """Represent the addition of two sets
2804 """Represent the addition of two sets
2805
2805
2806 Wrapper structure for lazily adding two structures without losing much
2806 Wrapper structure for lazily adding two structures without losing much
2807 performance on the __contains__ method
2807 performance on the __contains__ method
2808
2808
2809 If the ascending attribute is set, that means the two structures are
2809 If the ascending attribute is set, that means the two structures are
2810 ordered in either an ascending or descending way. Therefore, we can add
2810 ordered in either an ascending or descending way. Therefore, we can add
2811 them maintaining the order by iterating over both at the same time
2811 them maintaining the order by iterating over both at the same time
2812 """
2812 """
2813 def __init__(self, revs1, revs2, ascending=None):
2813 def __init__(self, revs1, revs2, ascending=None):
2814 self._r1 = revs1
2814 self._r1 = revs1
2815 self._r2 = revs2
2815 self._r2 = revs2
2816 self._iter = None
2816 self._iter = None
2817 self._ascending = ascending
2817 self._ascending = ascending
2818 self._genlist = None
2818 self._genlist = None
2819 self._asclist = None
2819 self._asclist = None
2820
2820
2821 def __len__(self):
2821 def __len__(self):
2822 return len(self._list)
2822 return len(self._list)
2823
2823
2824 def __nonzero__(self):
2824 def __nonzero__(self):
2825 return bool(self._r1) or bool(self._r2)
2825 return bool(self._r1) or bool(self._r2)
2826
2826
2827 @util.propertycache
2827 @util.propertycache
2828 def _list(self):
2828 def _list(self):
2829 if not self._genlist:
2829 if not self._genlist:
2830 self._genlist = baseset(self._iterator())
2830 self._genlist = baseset(self._iterator())
2831 return self._genlist
2831 return self._genlist
2832
2832
2833 def _iterator(self):
2833 def _iterator(self):
2834 """Iterate over both collections without repeating elements
2834 """Iterate over both collections without repeating elements
2835
2835
2836 If the ascending attribute is not set, iterate over the first one and
2836 If the ascending attribute is not set, iterate over the first one and
2837 then over the second one checking for membership on the first one so we
2837 then over the second one checking for membership on the first one so we
2838 dont yield any duplicates.
2838 dont yield any duplicates.
2839
2839
2840 If the ascending attribute is set, iterate over both collections at the
2840 If the ascending attribute is set, iterate over both collections at the
2841 same time, yielding only one value at a time in the given order.
2841 same time, yielding only one value at a time in the given order.
2842 """
2842 """
2843 if self._ascending is None:
2843 if self._ascending is None:
2844 def gen():
2844 def gen():
2845 for r in self._r1:
2845 for r in self._r1:
2846 yield r
2846 yield r
2847 inr1 = self._r1.__contains__
2847 inr1 = self._r1.__contains__
2848 for r in self._r2:
2848 for r in self._r2:
2849 if not inr1(r):
2849 if not inr1(r):
2850 yield r
2850 yield r
2851 gen = gen()
2851 gen = gen()
2852 else:
2852 else:
2853 iter1 = iter(self._r1)
2853 iter1 = iter(self._r1)
2854 iter2 = iter(self._r2)
2854 iter2 = iter(self._r2)
2855 gen = self._iterordered(self._ascending, iter1, iter2)
2855 gen = self._iterordered(self._ascending, iter1, iter2)
2856 return gen
2856 return gen
2857
2857
2858 def __iter__(self):
2858 def __iter__(self):
2859 if self._ascending is None:
2859 if self._ascending is None:
2860 if self._genlist:
2860 if self._genlist:
2861 return iter(self._genlist)
2861 return iter(self._genlist)
2862 return iter(self._iterator())
2862 return iter(self._iterator())
2863 self._trysetasclist()
2863 self._trysetasclist()
2864 if self._ascending:
2864 if self._ascending:
2865 it = self.fastasc
2865 it = self.fastasc
2866 else:
2866 else:
2867 it = self.fastdesc
2867 it = self.fastdesc
2868 if it is None:
2868 if it is None:
2869 # consume the gen and try again
2869 # consume the gen and try again
2870 self._list
2870 self._list
2871 return iter(self)
2871 return iter(self)
2872 return it()
2872 return it()
2873
2873
2874 def _trysetasclist(self):
2874 def _trysetasclist(self):
2875 """populate the _asclist attribute if possible and necessary"""
2875 """populate the _asclist attribute if possible and necessary"""
2876 if self._genlist is not None and self._asclist is None:
2876 if self._genlist is not None and self._asclist is None:
2877 self._asclist = sorted(self._genlist)
2877 self._asclist = sorted(self._genlist)
2878
2878
2879 @property
2879 @property
2880 def fastasc(self):
2880 def fastasc(self):
2881 self._trysetasclist()
2881 self._trysetasclist()
2882 if self._asclist is not None:
2882 if self._asclist is not None:
2883 return self._asclist.__iter__
2883 return self._asclist.__iter__
2884 iter1 = self._r1.fastasc
2884 iter1 = self._r1.fastasc
2885 iter2 = self._r2.fastasc
2885 iter2 = self._r2.fastasc
2886 if None in (iter1, iter2):
2886 if None in (iter1, iter2):
2887 return None
2887 return None
2888 return lambda: self._iterordered(True, iter1(), iter2())
2888 return lambda: self._iterordered(True, iter1(), iter2())
2889
2889
2890 @property
2890 @property
2891 def fastdesc(self):
2891 def fastdesc(self):
2892 self._trysetasclist()
2892 self._trysetasclist()
2893 if self._asclist is not None:
2893 if self._asclist is not None:
2894 return self._asclist.__reversed__
2894 return self._asclist.__reversed__
2895 iter1 = self._r1.fastdesc
2895 iter1 = self._r1.fastdesc
2896 iter2 = self._r2.fastdesc
2896 iter2 = self._r2.fastdesc
2897 if None in (iter1, iter2):
2897 if None in (iter1, iter2):
2898 return None
2898 return None
2899 return lambda: self._iterordered(False, iter1(), iter2())
2899 return lambda: self._iterordered(False, iter1(), iter2())
2900
2900
2901 def _iterordered(self, ascending, iter1, iter2):
2901 def _iterordered(self, ascending, iter1, iter2):
2902 """produce an ordered iteration from two iterators with the same order
2902 """produce an ordered iteration from two iterators with the same order
2903
2903
2904 The ascending is used to indicated the iteration direction.
2904 The ascending is used to indicated the iteration direction.
2905 """
2905 """
2906 choice = max
2906 choice = max
2907 if ascending:
2907 if ascending:
2908 choice = min
2908 choice = min
2909
2909
2910 val1 = None
2910 val1 = None
2911 val2 = None
2911 val2 = None
2912
2912
2913 choice = max
2913 choice = max
2914 if ascending:
2914 if ascending:
2915 choice = min
2915 choice = min
2916 try:
2916 try:
2917 # Consume both iterators in an ordered way until one is
2917 # Consume both iterators in an ordered way until one is
2918 # empty
2918 # empty
2919 while True:
2919 while True:
2920 if val1 is None:
2920 if val1 is None:
2921 val1 = iter1.next()
2921 val1 = iter1.next()
2922 if val2 is None:
2922 if val2 is None:
2923 val2 = iter2.next()
2923 val2 = iter2.next()
2924 next = choice(val1, val2)
2924 next = choice(val1, val2)
2925 yield next
2925 yield next
2926 if val1 == next:
2926 if val1 == next:
2927 val1 = None
2927 val1 = None
2928 if val2 == next:
2928 if val2 == next:
2929 val2 = None
2929 val2 = None
2930 except StopIteration:
2930 except StopIteration:
2931 # Flush any remaining values and consume the other one
2931 # Flush any remaining values and consume the other one
2932 it = iter2
2932 it = iter2
2933 if val1 is not None:
2933 if val1 is not None:
2934 yield val1
2934 yield val1
2935 it = iter1
2935 it = iter1
2936 elif val2 is not None:
2936 elif val2 is not None:
2937 # might have been equality and both are empty
2937 # might have been equality and both are empty
2938 yield val2
2938 yield val2
2939 for val in it:
2939 for val in it:
2940 yield val
2940 yield val
2941
2941
2942 def __contains__(self, x):
2942 def __contains__(self, x):
2943 return x in self._r1 or x in self._r2
2943 return x in self._r1 or x in self._r2
2944
2944
2945 def sort(self, reverse=False):
2945 def sort(self, reverse=False):
2946 """Sort the added set
2946 """Sort the added set
2947
2947
2948 For this we use the cached list with all the generated values and if we
2948 For this we use the cached list with all the generated values and if we
2949 know they are ascending or descending we can sort them in a smart way.
2949 know they are ascending or descending we can sort them in a smart way.
2950 """
2950 """
2951 self._ascending = not reverse
2951 self._ascending = not reverse
2952
2952
2953 def isascending(self):
2953 def isascending(self):
2954 return self._ascending is not None and self._ascending
2954 return self._ascending is not None and self._ascending
2955
2955
2956 def isdescending(self):
2956 def isdescending(self):
2957 return self._ascending is not None and not self._ascending
2957 return self._ascending is not None and not self._ascending
2958
2958
2959 def reverse(self):
2959 def reverse(self):
2960 if self._ascending is None:
2960 if self._ascending is None:
2961 self._list.reverse()
2961 self._list.reverse()
2962 else:
2962 else:
2963 self._ascending = not self._ascending
2963 self._ascending = not self._ascending
2964
2964
2965 def first(self):
2965 def first(self):
2966 for x in self:
2966 for x in self:
2967 return x
2967 return x
2968 return None
2968 return None
2969
2969
2970 def last(self):
2970 def last(self):
2971 self.reverse()
2971 self.reverse()
2972 val = self.first()
2972 val = self.first()
2973 self.reverse()
2973 self.reverse()
2974 return val
2974 return val
2975
2975
2976 class generatorset(abstractsmartset):
2976 class generatorset(abstractsmartset):
2977 """Wrap a generator for lazy iteration
2977 """Wrap a generator for lazy iteration
2978
2978
2979 Wrapper structure for generators that provides lazy membership and can
2979 Wrapper structure for generators that provides lazy membership and can
2980 be iterated more than once.
2980 be iterated more than once.
2981 When asked for membership it generates values until either it finds the
2981 When asked for membership it generates values until either it finds the
2982 requested one or has gone through all the elements in the generator
2982 requested one or has gone through all the elements in the generator
2983 """
2983 """
2984 def __init__(self, gen, iterasc=None):
2984 def __init__(self, gen, iterasc=None):
2985 """
2985 """
2986 gen: a generator producing the values for the generatorset.
2986 gen: a generator producing the values for the generatorset.
2987 """
2987 """
2988 self._gen = gen
2988 self._gen = gen
2989 self._asclist = None
2989 self._asclist = None
2990 self._cache = {}
2990 self._cache = {}
2991 self._genlist = []
2991 self._genlist = []
2992 self._finished = False
2992 self._finished = False
2993 self._ascending = True
2993 self._ascending = True
2994 if iterasc is not None:
2994 if iterasc is not None:
2995 if iterasc:
2995 if iterasc:
2996 self.fastasc = self._iterator
2996 self.fastasc = self._iterator
2997 self.__contains__ = self._asccontains
2997 self.__contains__ = self._asccontains
2998 else:
2998 else:
2999 self.fastdesc = self._iterator
2999 self.fastdesc = self._iterator
3000 self.__contains__ = self._desccontains
3000 self.__contains__ = self._desccontains
3001
3001
3002 def __nonzero__(self):
3002 def __nonzero__(self):
3003 for r in self:
3003 for r in self:
3004 return True
3004 return True
3005 return False
3005 return False
3006
3006
3007 def __contains__(self, x):
3007 def __contains__(self, x):
3008 if x in self._cache:
3008 if x in self._cache:
3009 return self._cache[x]
3009 return self._cache[x]
3010
3010
3011 # Use new values only, as existing values would be cached.
3011 # Use new values only, as existing values would be cached.
3012 for l in self._consumegen():
3012 for l in self._consumegen():
3013 if l == x:
3013 if l == x:
3014 return True
3014 return True
3015
3015
3016 self._cache[x] = False
3016 self._cache[x] = False
3017 return False
3017 return False
3018
3018
3019 def _asccontains(self, x):
3019 def _asccontains(self, x):
3020 """version of contains optimised for ascending generator"""
3020 """version of contains optimised for ascending generator"""
3021 if x in self._cache:
3021 if x in self._cache:
3022 return self._cache[x]
3022 return self._cache[x]
3023
3023
3024 # Use new values only, as existing values would be cached.
3024 # Use new values only, as existing values would be cached.
3025 for l in self._consumegen():
3025 for l in self._consumegen():
3026 if l == x:
3026 if l == x:
3027 return True
3027 return True
3028 if l > x:
3028 if l > x:
3029 break
3029 break
3030
3030
3031 self._cache[x] = False
3031 self._cache[x] = False
3032 return False
3032 return False
3033
3033
3034 def _desccontains(self, x):
3034 def _desccontains(self, x):
3035 """version of contains optimised for descending generator"""
3035 """version of contains optimised for descending generator"""
3036 if x in self._cache:
3036 if x in self._cache:
3037 return self._cache[x]
3037 return self._cache[x]
3038
3038
3039 # Use new values only, as existing values would be cached.
3039 # Use new values only, as existing values would be cached.
3040 for l in self._consumegen():
3040 for l in self._consumegen():
3041 if l == x:
3041 if l == x:
3042 return True
3042 return True
3043 if l < x:
3043 if l < x:
3044 break
3044 break
3045
3045
3046 self._cache[x] = False
3046 self._cache[x] = False
3047 return False
3047 return False
3048
3048
3049 def __iter__(self):
3049 def __iter__(self):
3050 if self._ascending:
3050 if self._ascending:
3051 it = self.fastasc
3051 it = self.fastasc
3052 else:
3052 else:
3053 it = self.fastdesc
3053 it = self.fastdesc
3054 if it is not None:
3054 if it is not None:
3055 return it()
3055 return it()
3056 # we need to consume the iterator
3056 # we need to consume the iterator
3057 for x in self._consumegen():
3057 for x in self._consumegen():
3058 pass
3058 pass
3059 # recall the same code
3059 # recall the same code
3060 return iter(self)
3060 return iter(self)
3061
3061
3062 def _iterator(self):
3062 def _iterator(self):
3063 if self._finished:
3063 if self._finished:
3064 return iter(self._genlist)
3064 return iter(self._genlist)
3065
3065
3066 # We have to use this complex iteration strategy to allow multiple
3066 # We have to use this complex iteration strategy to allow multiple
3067 # iterations at the same time. We need to be able to catch revision
3067 # iterations at the same time. We need to be able to catch revision
3068 # removed from _consumegen and added to genlist in another instance.
3068 # removed from _consumegen and added to genlist in another instance.
3069 #
3069 #
3070 # Getting rid of it would provide an about 15% speed up on this
3070 # Getting rid of it would provide an about 15% speed up on this
3071 # iteration.
3071 # iteration.
3072 genlist = self._genlist
3072 genlist = self._genlist
3073 nextrev = self._consumegen().next
3073 nextrev = self._consumegen().next
3074 _len = len # cache global lookup
3074 _len = len # cache global lookup
3075 def gen():
3075 def gen():
3076 i = 0
3076 i = 0
3077 while True:
3077 while True:
3078 if i < _len(genlist):
3078 if i < _len(genlist):
3079 yield genlist[i]
3079 yield genlist[i]
3080 else:
3080 else:
3081 yield nextrev()
3081 yield nextrev()
3082 i += 1
3082 i += 1
3083 return gen()
3083 return gen()
3084
3084
3085 def _consumegen(self):
3085 def _consumegen(self):
3086 cache = self._cache
3086 cache = self._cache
3087 genlist = self._genlist.append
3087 genlist = self._genlist.append
3088 for item in self._gen:
3088 for item in self._gen:
3089 cache[item] = True
3089 cache[item] = True
3090 genlist(item)
3090 genlist(item)
3091 yield item
3091 yield item
3092 if not self._finished:
3092 if not self._finished:
3093 self._finished = True
3093 self._finished = True
3094 asc = self._genlist[:]
3094 asc = self._genlist[:]
3095 asc.sort()
3095 asc.sort()
3096 self._asclist = asc
3096 self._asclist = asc
3097 self.fastasc = asc.__iter__
3097 self.fastasc = asc.__iter__
3098 self.fastdesc = asc.__reversed__
3098 self.fastdesc = asc.__reversed__
3099
3099
3100 def __len__(self):
3100 def __len__(self):
3101 for x in self._consumegen():
3101 for x in self._consumegen():
3102 pass
3102 pass
3103 return len(self._genlist)
3103 return len(self._genlist)
3104
3104
3105 def sort(self, reverse=False):
3105 def sort(self, reverse=False):
3106 self._ascending = not reverse
3106 self._ascending = not reverse
3107
3107
3108 def reverse(self):
3108 def reverse(self):
3109 self._ascending = not self._ascending
3109 self._ascending = not self._ascending
3110
3110
3111 def isascending(self):
3111 def isascending(self):
3112 return self._ascending
3112 return self._ascending
3113
3113
3114 def isdescending(self):
3114 def isdescending(self):
3115 return not self._ascending
3115 return not self._ascending
3116
3116
3117 def first(self):
3117 def first(self):
3118 if self._ascending:
3118 if self._ascending:
3119 it = self.fastasc
3119 it = self.fastasc
3120 else:
3120 else:
3121 it = self.fastdesc
3121 it = self.fastdesc
3122 if it is None:
3122 if it is None:
3123 # we need to consume all and try again
3123 # we need to consume all and try again
3124 for x in self._consumegen():
3124 for x in self._consumegen():
3125 pass
3125 pass
3126 return self.first()
3126 return self.first()
3127 if self:
3127 if self:
3128 return it().next()
3128 return it().next()
3129 return None
3129 return None
3130
3130
3131 def last(self):
3131 def last(self):
3132 if self._ascending:
3132 if self._ascending:
3133 it = self.fastdesc
3133 it = self.fastdesc
3134 else:
3134 else:
3135 it = self.fastasc
3135 it = self.fastasc
3136 if it is None:
3136 if it is None:
3137 # we need to consume all and try again
3137 # we need to consume all and try again
3138 for x in self._consumegen():
3138 for x in self._consumegen():
3139 pass
3139 pass
3140 return self.first()
3140 return self.first()
3141 if self:
3141 if self:
3142 return it().next()
3142 return it().next()
3143 return None
3143 return None
3144
3144
3145 def spanset(repo, start=None, end=None):
3145 def spanset(repo, start=None, end=None):
3146 """factory function to dispatch between fullreposet and actual spanset
3146 """factory function to dispatch between fullreposet and actual spanset
3147
3147
3148 Feel free to update all spanset call sites and kill this function at some
3148 Feel free to update all spanset call sites and kill this function at some
3149 point.
3149 point.
3150 """
3150 """
3151 if start is None and end is None:
3151 if start is None and end is None:
3152 return fullreposet(repo)
3152 return fullreposet(repo)
3153 return _spanset(repo, start, end)
3153 return _spanset(repo, start, end)
3154
3154
3155
3155
3156 class _spanset(abstractsmartset):
3156 class _spanset(abstractsmartset):
3157 """Duck type for baseset class which represents a range of revisions and
3157 """Duck type for baseset class which represents a range of revisions and
3158 can work lazily and without having all the range in memory
3158 can work lazily and without having all the range in memory
3159
3159
3160 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3160 Note that spanset(x, y) behave almost like xrange(x, y) except for two
3161 notable points:
3161 notable points:
3162 - when x < y it will be automatically descending,
3162 - when x < y it will be automatically descending,
3163 - revision filtered with this repoview will be skipped.
3163 - revision filtered with this repoview will be skipped.
3164
3164
3165 """
3165 """
3166 def __init__(self, repo, start=0, end=None):
3166 def __init__(self, repo, start=0, end=None):
3167 """
3167 """
3168 start: first revision included the set
3168 start: first revision included the set
3169 (default to 0)
3169 (default to 0)
3170 end: first revision excluded (last+1)
3170 end: first revision excluded (last+1)
3171 (default to len(repo)
3171 (default to len(repo)
3172
3172
3173 Spanset will be descending if `end` < `start`.
3173 Spanset will be descending if `end` < `start`.
3174 """
3174 """
3175 if end is None:
3175 if end is None:
3176 end = len(repo)
3176 end = len(repo)
3177 self._ascending = start <= end
3177 self._ascending = start <= end
3178 if not self._ascending:
3178 if not self._ascending:
3179 start, end = end + 1, start +1
3179 start, end = end + 1, start +1
3180 self._start = start
3180 self._start = start
3181 self._end = end
3181 self._end = end
3182 self._hiddenrevs = repo.changelog.filteredrevs
3182 self._hiddenrevs = repo.changelog.filteredrevs
3183
3183
3184 def sort(self, reverse=False):
3184 def sort(self, reverse=False):
3185 self._ascending = not reverse
3185 self._ascending = not reverse
3186
3186
3187 def reverse(self):
3187 def reverse(self):
3188 self._ascending = not self._ascending
3188 self._ascending = not self._ascending
3189
3189
3190 def _iterfilter(self, iterrange):
3190 def _iterfilter(self, iterrange):
3191 s = self._hiddenrevs
3191 s = self._hiddenrevs
3192 for r in iterrange:
3192 for r in iterrange:
3193 if r not in s:
3193 if r not in s:
3194 yield r
3194 yield r
3195
3195
3196 def __iter__(self):
3196 def __iter__(self):
3197 if self._ascending:
3197 if self._ascending:
3198 return self.fastasc()
3198 return self.fastasc()
3199 else:
3199 else:
3200 return self.fastdesc()
3200 return self.fastdesc()
3201
3201
3202 def fastasc(self):
3202 def fastasc(self):
3203 iterrange = xrange(self._start, self._end)
3203 iterrange = xrange(self._start, self._end)
3204 if self._hiddenrevs:
3204 if self._hiddenrevs:
3205 return self._iterfilter(iterrange)
3205 return self._iterfilter(iterrange)
3206 return iter(iterrange)
3206 return iter(iterrange)
3207
3207
3208 def fastdesc(self):
3208 def fastdesc(self):
3209 iterrange = xrange(self._end - 1, self._start - 1, -1)
3209 iterrange = xrange(self._end - 1, self._start - 1, -1)
3210 if self._hiddenrevs:
3210 if self._hiddenrevs:
3211 return self._iterfilter(iterrange)
3211 return self._iterfilter(iterrange)
3212 return iter(iterrange)
3212 return iter(iterrange)
3213
3213
3214 def __contains__(self, rev):
3214 def __contains__(self, rev):
3215 hidden = self._hiddenrevs
3215 hidden = self._hiddenrevs
3216 return ((self._start <= rev < self._end)
3216 return ((self._start <= rev < self._end)
3217 and not (hidden and rev in hidden))
3217 and not (hidden and rev in hidden))
3218
3218
3219 def __nonzero__(self):
3219 def __nonzero__(self):
3220 for r in self:
3220 for r in self:
3221 return True
3221 return True
3222 return False
3222 return False
3223
3223
3224 def __len__(self):
3224 def __len__(self):
3225 if not self._hiddenrevs:
3225 if not self._hiddenrevs:
3226 return abs(self._end - self._start)
3226 return abs(self._end - self._start)
3227 else:
3227 else:
3228 count = 0
3228 count = 0
3229 start = self._start
3229 start = self._start
3230 end = self._end
3230 end = self._end
3231 for rev in self._hiddenrevs:
3231 for rev in self._hiddenrevs:
3232 if (end < rev <= start) or (start <= rev < end):
3232 if (end < rev <= start) or (start <= rev < end):
3233 count += 1
3233 count += 1
3234 return abs(self._end - self._start) - count
3234 return abs(self._end - self._start) - count
3235
3235
3236 def isascending(self):
3236 def isascending(self):
3237 return self._ascending
3237 return self._ascending
3238
3238
3239 def isdescending(self):
3239 def isdescending(self):
3240 return not self._ascending
3240 return not self._ascending
3241
3241
3242 def first(self):
3242 def first(self):
3243 if self._ascending:
3243 if self._ascending:
3244 it = self.fastasc
3244 it = self.fastasc
3245 else:
3245 else:
3246 it = self.fastdesc
3246 it = self.fastdesc
3247 for x in it():
3247 for x in it():
3248 return x
3248 return x
3249 return None
3249 return None
3250
3250
3251 def last(self):
3251 def last(self):
3252 if self._ascending:
3252 if self._ascending:
3253 it = self.fastdesc
3253 it = self.fastdesc
3254 else:
3254 else:
3255 it = self.fastasc
3255 it = self.fastasc
3256 for x in it():
3256 for x in it():
3257 return x
3257 return x
3258 return None
3258 return None
3259
3259
3260 class fullreposet(_spanset):
3260 class fullreposet(_spanset):
3261 """a set containing all revisions in the repo
3261 """a set containing all revisions in the repo
3262
3262
3263 This class exists to host special optimization.
3263 This class exists to host special optimization.
3264 """
3264 """
3265
3265
3266 def __init__(self, repo):
3266 def __init__(self, repo):
3267 super(fullreposet, self).__init__(repo)
3267 super(fullreposet, self).__init__(repo)
3268
3268
3269 def __and__(self, other):
3269 def __and__(self, other):
3270 """As self contains the whole repo, all of the other set should also be
3270 """As self contains the whole repo, all of the other set should also be
3271 in self. Therefore `self & other = other`.
3271 in self. Therefore `self & other = other`.
3272
3272
3273 This boldly assumes the other contains valid revs only.
3273 This boldly assumes the other contains valid revs only.
3274 """
3274 """
3275 # other not a smartset, make is so
3275 # other not a smartset, make is so
3276 if not util.safehasattr(other, 'isascending'):
3276 if not util.safehasattr(other, 'isascending'):
3277 # filter out hidden revision
3277 # filter out hidden revision
3278 # (this boldly assumes all smartset are pure)
3278 # (this boldly assumes all smartset are pure)
3279 #
3279 #
3280 # `other` was used with "&", let's assume this is a set like
3280 # `other` was used with "&", let's assume this is a set like
3281 # object.
3281 # object.
3282 other = baseset(other - self._hiddenrevs)
3282 other = baseset(other - self._hiddenrevs)
3283
3283
3284 other.sort(reverse=self.isdescending())
3284 other.sort(reverse=self.isdescending())
3285 return other
3285 return other
3286
3286
3287 # tell hggettext to extract docstrings from these functions:
3287 # tell hggettext to extract docstrings from these functions:
3288 i18nfunctions = symbols.values()
3288 i18nfunctions = symbols.values()
@@ -1,1918 +1,1932 b''
1 Log on empty repository: checking consistency
1 Log on empty repository: checking consistency
2
2
3 $ hg init empty
3 $ hg init empty
4 $ cd empty
4 $ cd empty
5 $ hg log
5 $ hg log
6 $ hg log -r 1
6 $ hg log -r 1
7 abort: unknown revision '1'!
7 abort: unknown revision '1'!
8 [255]
8 [255]
9 $ hg log -r -1:0
9 $ hg log -r -1:0
10 abort: unknown revision '-1'!
10 abort: unknown revision '-1'!
11 [255]
11 [255]
12 $ hg log -r 'branch(name)'
12 $ hg log -r 'branch(name)'
13 abort: unknown revision 'name'!
13 abort: unknown revision 'name'!
14 [255]
14 [255]
15 $ hg log -r null -q
15 $ hg log -r null -q
16 -1:000000000000
16 -1:000000000000
17
17
18 The g is crafted to have 2 filelog topological heads in a linear
18 The g is crafted to have 2 filelog topological heads in a linear
19 changeset graph
19 changeset graph
20
20
21 $ hg init a
21 $ hg init a
22 $ cd a
22 $ cd a
23 $ echo a > a
23 $ echo a > a
24 $ echo f > f
24 $ echo f > f
25 $ hg ci -Ama -d '1 0'
25 $ hg ci -Ama -d '1 0'
26 adding a
26 adding a
27 adding f
27 adding f
28
28
29 $ hg cp a b
29 $ hg cp a b
30 $ hg cp f g
30 $ hg cp f g
31 $ hg ci -mb -d '2 0'
31 $ hg ci -mb -d '2 0'
32
32
33 $ mkdir dir
33 $ mkdir dir
34 $ hg mv b dir
34 $ hg mv b dir
35 $ echo g >> g
35 $ echo g >> g
36 $ echo f >> f
36 $ echo f >> f
37 $ hg ci -mc -d '3 0'
37 $ hg ci -mc -d '3 0'
38
38
39 $ hg mv a b
39 $ hg mv a b
40 $ hg cp -f f g
40 $ hg cp -f f g
41 $ echo a > d
41 $ echo a > d
42 $ hg add d
42 $ hg add d
43 $ hg ci -md -d '4 0'
43 $ hg ci -md -d '4 0'
44
44
45 $ hg mv dir/b e
45 $ hg mv dir/b e
46 $ hg ci -me -d '5 0'
46 $ hg ci -me -d '5 0'
47
47
48 $ hg log a
48 $ hg log a
49 changeset: 0:9161b9aeaf16
49 changeset: 0:9161b9aeaf16
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:01 1970 +0000
51 date: Thu Jan 01 00:00:01 1970 +0000
52 summary: a
52 summary: a
53
53
54 log on directory
54 log on directory
55
55
56 $ hg log dir
56 $ hg log dir
57 changeset: 4:7e4639b4691b
57 changeset: 4:7e4639b4691b
58 tag: tip
58 tag: tip
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:05 1970 +0000
60 date: Thu Jan 01 00:00:05 1970 +0000
61 summary: e
61 summary: e
62
62
63 changeset: 2:f8954cd4dc1f
63 changeset: 2:f8954cd4dc1f
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:03 1970 +0000
65 date: Thu Jan 01 00:00:03 1970 +0000
66 summary: c
66 summary: c
67
67
68 $ hg log somethingthatdoesntexist dir
68 $ hg log somethingthatdoesntexist dir
69 changeset: 4:7e4639b4691b
69 changeset: 4:7e4639b4691b
70 tag: tip
70 tag: tip
71 user: test
71 user: test
72 date: Thu Jan 01 00:00:05 1970 +0000
72 date: Thu Jan 01 00:00:05 1970 +0000
73 summary: e
73 summary: e
74
74
75 changeset: 2:f8954cd4dc1f
75 changeset: 2:f8954cd4dc1f
76 user: test
76 user: test
77 date: Thu Jan 01 00:00:03 1970 +0000
77 date: Thu Jan 01 00:00:03 1970 +0000
78 summary: c
78 summary: c
79
79
80
80
81 -f, non-existent directory
81 -f, non-existent directory
82
82
83 $ hg log -f dir
83 $ hg log -f dir
84 abort: cannot follow file not in parent revision: "dir"
84 abort: cannot follow file not in parent revision: "dir"
85 [255]
85 [255]
86
86
87 -f, directory
87 -f, directory
88
88
89 $ hg up -q 3
89 $ hg up -q 3
90 $ hg log -f dir
90 $ hg log -f dir
91 changeset: 2:f8954cd4dc1f
91 changeset: 2:f8954cd4dc1f
92 user: test
92 user: test
93 date: Thu Jan 01 00:00:03 1970 +0000
93 date: Thu Jan 01 00:00:03 1970 +0000
94 summary: c
94 summary: c
95
95
96 -f, directory with --patch
96 -f, directory with --patch
97
97
98 $ hg log -f dir -p
98 $ hg log -f dir -p
99 changeset: 2:f8954cd4dc1f
99 changeset: 2:f8954cd4dc1f
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:03 1970 +0000
101 date: Thu Jan 01 00:00:03 1970 +0000
102 summary: c
102 summary: c
103
103
104 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
104 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
105 --- /dev/null* (glob)
105 --- /dev/null* (glob)
106 +++ b/dir/b* (glob)
106 +++ b/dir/b* (glob)
107 @@ -0,0 +1,1 @@
107 @@ -0,0 +1,1 @@
108 +a
108 +a
109
109
110
110
111 -f, pattern
111 -f, pattern
112
112
113 $ hg log -f -I 'dir**' -p
113 $ hg log -f -I 'dir**' -p
114 changeset: 2:f8954cd4dc1f
114 changeset: 2:f8954cd4dc1f
115 user: test
115 user: test
116 date: Thu Jan 01 00:00:03 1970 +0000
116 date: Thu Jan 01 00:00:03 1970 +0000
117 summary: c
117 summary: c
118
118
119 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
119 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
120 --- /dev/null* (glob)
120 --- /dev/null* (glob)
121 +++ b/dir/b* (glob)
121 +++ b/dir/b* (glob)
122 @@ -0,0 +1,1 @@
122 @@ -0,0 +1,1 @@
123 +a
123 +a
124
124
125 $ hg up -q 4
125 $ hg up -q 4
126
126
127 -f, a wrong style
127 -f, a wrong style
128
128
129 $ hg log -f -l1 --style something
129 $ hg log -f -l1 --style something
130 abort: style 'something' not found
130 abort: style 'something' not found
131 (available styles: bisect, changelog, compact, default, phases, xml)
131 (available styles: bisect, changelog, compact, default, phases, xml)
132 [255]
132 [255]
133
133
134 -f, phases style
134 -f, phases style
135
135
136
136
137 $ hg log -f -l1 --style phases
137 $ hg log -f -l1 --style phases
138 changeset: 4:7e4639b4691b
138 changeset: 4:7e4639b4691b
139 tag: tip
139 tag: tip
140 phase: draft
140 phase: draft
141 user: test
141 user: test
142 date: Thu Jan 01 00:00:05 1970 +0000
142 date: Thu Jan 01 00:00:05 1970 +0000
143 summary: e
143 summary: e
144
144
145
145
146 -f, but no args
146 -f, but no args
147
147
148 $ hg log -f
148 $ hg log -f
149 changeset: 4:7e4639b4691b
149 changeset: 4:7e4639b4691b
150 tag: tip
150 tag: tip
151 user: test
151 user: test
152 date: Thu Jan 01 00:00:05 1970 +0000
152 date: Thu Jan 01 00:00:05 1970 +0000
153 summary: e
153 summary: e
154
154
155 changeset: 3:2ca5ba701980
155 changeset: 3:2ca5ba701980
156 user: test
156 user: test
157 date: Thu Jan 01 00:00:04 1970 +0000
157 date: Thu Jan 01 00:00:04 1970 +0000
158 summary: d
158 summary: d
159
159
160 changeset: 2:f8954cd4dc1f
160 changeset: 2:f8954cd4dc1f
161 user: test
161 user: test
162 date: Thu Jan 01 00:00:03 1970 +0000
162 date: Thu Jan 01 00:00:03 1970 +0000
163 summary: c
163 summary: c
164
164
165 changeset: 1:d89b0a12d229
165 changeset: 1:d89b0a12d229
166 user: test
166 user: test
167 date: Thu Jan 01 00:00:02 1970 +0000
167 date: Thu Jan 01 00:00:02 1970 +0000
168 summary: b
168 summary: b
169
169
170 changeset: 0:9161b9aeaf16
170 changeset: 0:9161b9aeaf16
171 user: test
171 user: test
172 date: Thu Jan 01 00:00:01 1970 +0000
172 date: Thu Jan 01 00:00:01 1970 +0000
173 summary: a
173 summary: a
174
174
175
175
176 one rename
176 one rename
177
177
178 $ hg up -q 2
178 $ hg up -q 2
179 $ hg log -vf a
179 $ hg log -vf a
180 changeset: 0:9161b9aeaf16
180 changeset: 0:9161b9aeaf16
181 user: test
181 user: test
182 date: Thu Jan 01 00:00:01 1970 +0000
182 date: Thu Jan 01 00:00:01 1970 +0000
183 files: a f
183 files: a f
184 description:
184 description:
185 a
185 a
186
186
187
187
188
188
189 many renames
189 many renames
190
190
191 $ hg up -q tip
191 $ hg up -q tip
192 $ hg log -vf e
192 $ hg log -vf e
193 changeset: 4:7e4639b4691b
193 changeset: 4:7e4639b4691b
194 tag: tip
194 tag: tip
195 user: test
195 user: test
196 date: Thu Jan 01 00:00:05 1970 +0000
196 date: Thu Jan 01 00:00:05 1970 +0000
197 files: dir/b e
197 files: dir/b e
198 description:
198 description:
199 e
199 e
200
200
201
201
202 changeset: 2:f8954cd4dc1f
202 changeset: 2:f8954cd4dc1f
203 user: test
203 user: test
204 date: Thu Jan 01 00:00:03 1970 +0000
204 date: Thu Jan 01 00:00:03 1970 +0000
205 files: b dir/b f g
205 files: b dir/b f g
206 description:
206 description:
207 c
207 c
208
208
209
209
210 changeset: 1:d89b0a12d229
210 changeset: 1:d89b0a12d229
211 user: test
211 user: test
212 date: Thu Jan 01 00:00:02 1970 +0000
212 date: Thu Jan 01 00:00:02 1970 +0000
213 files: b g
213 files: b g
214 description:
214 description:
215 b
215 b
216
216
217
217
218 changeset: 0:9161b9aeaf16
218 changeset: 0:9161b9aeaf16
219 user: test
219 user: test
220 date: Thu Jan 01 00:00:01 1970 +0000
220 date: Thu Jan 01 00:00:01 1970 +0000
221 files: a f
221 files: a f
222 description:
222 description:
223 a
223 a
224
224
225
225
226
226
227
227
228 log -pf dir/b
228 log -pf dir/b
229
229
230 $ hg up -q 3
230 $ hg up -q 3
231 $ hg log -pf dir/b
231 $ hg log -pf dir/b
232 changeset: 2:f8954cd4dc1f
232 changeset: 2:f8954cd4dc1f
233 user: test
233 user: test
234 date: Thu Jan 01 00:00:03 1970 +0000
234 date: Thu Jan 01 00:00:03 1970 +0000
235 summary: c
235 summary: c
236
236
237 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
237 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
238 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
238 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
239 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
239 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
240 @@ -0,0 +1,1 @@
240 @@ -0,0 +1,1 @@
241 +a
241 +a
242
242
243 changeset: 1:d89b0a12d229
243 changeset: 1:d89b0a12d229
244 user: test
244 user: test
245 date: Thu Jan 01 00:00:02 1970 +0000
245 date: Thu Jan 01 00:00:02 1970 +0000
246 summary: b
246 summary: b
247
247
248 diff -r 9161b9aeaf16 -r d89b0a12d229 b
248 diff -r 9161b9aeaf16 -r d89b0a12d229 b
249 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
249 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
250 +++ b/b Thu Jan 01 00:00:02 1970 +0000
250 +++ b/b Thu Jan 01 00:00:02 1970 +0000
251 @@ -0,0 +1,1 @@
251 @@ -0,0 +1,1 @@
252 +a
252 +a
253
253
254 changeset: 0:9161b9aeaf16
254 changeset: 0:9161b9aeaf16
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:01 1970 +0000
256 date: Thu Jan 01 00:00:01 1970 +0000
257 summary: a
257 summary: a
258
258
259 diff -r 000000000000 -r 9161b9aeaf16 a
259 diff -r 000000000000 -r 9161b9aeaf16 a
260 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
260 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
261 +++ b/a Thu Jan 01 00:00:01 1970 +0000
261 +++ b/a Thu Jan 01 00:00:01 1970 +0000
262 @@ -0,0 +1,1 @@
262 @@ -0,0 +1,1 @@
263 +a
263 +a
264
264
265
265
266 log -pf b inside dir
266 log -pf b inside dir
267
267
268 $ hg --cwd=dir log -pf b
268 $ hg --cwd=dir log -pf b
269 changeset: 2:f8954cd4dc1f
269 changeset: 2:f8954cd4dc1f
270 user: test
270 user: test
271 date: Thu Jan 01 00:00:03 1970 +0000
271 date: Thu Jan 01 00:00:03 1970 +0000
272 summary: c
272 summary: c
273
273
274 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
274 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
275 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
276 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
277 @@ -0,0 +1,1 @@
277 @@ -0,0 +1,1 @@
278 +a
278 +a
279
279
280 changeset: 1:d89b0a12d229
280 changeset: 1:d89b0a12d229
281 user: test
281 user: test
282 date: Thu Jan 01 00:00:02 1970 +0000
282 date: Thu Jan 01 00:00:02 1970 +0000
283 summary: b
283 summary: b
284
284
285 diff -r 9161b9aeaf16 -r d89b0a12d229 b
285 diff -r 9161b9aeaf16 -r d89b0a12d229 b
286 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
286 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
287 +++ b/b Thu Jan 01 00:00:02 1970 +0000
287 +++ b/b Thu Jan 01 00:00:02 1970 +0000
288 @@ -0,0 +1,1 @@
288 @@ -0,0 +1,1 @@
289 +a
289 +a
290
290
291 changeset: 0:9161b9aeaf16
291 changeset: 0:9161b9aeaf16
292 user: test
292 user: test
293 date: Thu Jan 01 00:00:01 1970 +0000
293 date: Thu Jan 01 00:00:01 1970 +0000
294 summary: a
294 summary: a
295
295
296 diff -r 000000000000 -r 9161b9aeaf16 a
296 diff -r 000000000000 -r 9161b9aeaf16 a
297 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
297 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
298 +++ b/a Thu Jan 01 00:00:01 1970 +0000
298 +++ b/a Thu Jan 01 00:00:01 1970 +0000
299 @@ -0,0 +1,1 @@
299 @@ -0,0 +1,1 @@
300 +a
300 +a
301
301
302
302
303 log -pf, but no args
303 log -pf, but no args
304
304
305 $ hg log -pf
305 $ hg log -pf
306 changeset: 3:2ca5ba701980
306 changeset: 3:2ca5ba701980
307 user: test
307 user: test
308 date: Thu Jan 01 00:00:04 1970 +0000
308 date: Thu Jan 01 00:00:04 1970 +0000
309 summary: d
309 summary: d
310
310
311 diff -r f8954cd4dc1f -r 2ca5ba701980 a
311 diff -r f8954cd4dc1f -r 2ca5ba701980 a
312 --- a/a Thu Jan 01 00:00:03 1970 +0000
312 --- a/a Thu Jan 01 00:00:03 1970 +0000
313 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
313 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
314 @@ -1,1 +0,0 @@
314 @@ -1,1 +0,0 @@
315 -a
315 -a
316 diff -r f8954cd4dc1f -r 2ca5ba701980 b
316 diff -r f8954cd4dc1f -r 2ca5ba701980 b
317 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
317 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
318 +++ b/b Thu Jan 01 00:00:04 1970 +0000
318 +++ b/b Thu Jan 01 00:00:04 1970 +0000
319 @@ -0,0 +1,1 @@
319 @@ -0,0 +1,1 @@
320 +a
320 +a
321 diff -r f8954cd4dc1f -r 2ca5ba701980 d
321 diff -r f8954cd4dc1f -r 2ca5ba701980 d
322 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
322 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
323 +++ b/d Thu Jan 01 00:00:04 1970 +0000
323 +++ b/d Thu Jan 01 00:00:04 1970 +0000
324 @@ -0,0 +1,1 @@
324 @@ -0,0 +1,1 @@
325 +a
325 +a
326 diff -r f8954cd4dc1f -r 2ca5ba701980 g
326 diff -r f8954cd4dc1f -r 2ca5ba701980 g
327 --- a/g Thu Jan 01 00:00:03 1970 +0000
327 --- a/g Thu Jan 01 00:00:03 1970 +0000
328 +++ b/g Thu Jan 01 00:00:04 1970 +0000
328 +++ b/g Thu Jan 01 00:00:04 1970 +0000
329 @@ -1,2 +1,2 @@
329 @@ -1,2 +1,2 @@
330 f
330 f
331 -g
331 -g
332 +f
332 +f
333
333
334 changeset: 2:f8954cd4dc1f
334 changeset: 2:f8954cd4dc1f
335 user: test
335 user: test
336 date: Thu Jan 01 00:00:03 1970 +0000
336 date: Thu Jan 01 00:00:03 1970 +0000
337 summary: c
337 summary: c
338
338
339 diff -r d89b0a12d229 -r f8954cd4dc1f b
339 diff -r d89b0a12d229 -r f8954cd4dc1f b
340 --- a/b Thu Jan 01 00:00:02 1970 +0000
340 --- a/b Thu Jan 01 00:00:02 1970 +0000
341 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
341 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
342 @@ -1,1 +0,0 @@
342 @@ -1,1 +0,0 @@
343 -a
343 -a
344 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
344 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
345 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
345 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
346 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
346 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
347 @@ -0,0 +1,1 @@
347 @@ -0,0 +1,1 @@
348 +a
348 +a
349 diff -r d89b0a12d229 -r f8954cd4dc1f f
349 diff -r d89b0a12d229 -r f8954cd4dc1f f
350 --- a/f Thu Jan 01 00:00:02 1970 +0000
350 --- a/f Thu Jan 01 00:00:02 1970 +0000
351 +++ b/f Thu Jan 01 00:00:03 1970 +0000
351 +++ b/f Thu Jan 01 00:00:03 1970 +0000
352 @@ -1,1 +1,2 @@
352 @@ -1,1 +1,2 @@
353 f
353 f
354 +f
354 +f
355 diff -r d89b0a12d229 -r f8954cd4dc1f g
355 diff -r d89b0a12d229 -r f8954cd4dc1f g
356 --- a/g Thu Jan 01 00:00:02 1970 +0000
356 --- a/g Thu Jan 01 00:00:02 1970 +0000
357 +++ b/g Thu Jan 01 00:00:03 1970 +0000
357 +++ b/g Thu Jan 01 00:00:03 1970 +0000
358 @@ -1,1 +1,2 @@
358 @@ -1,1 +1,2 @@
359 f
359 f
360 +g
360 +g
361
361
362 changeset: 1:d89b0a12d229
362 changeset: 1:d89b0a12d229
363 user: test
363 user: test
364 date: Thu Jan 01 00:00:02 1970 +0000
364 date: Thu Jan 01 00:00:02 1970 +0000
365 summary: b
365 summary: b
366
366
367 diff -r 9161b9aeaf16 -r d89b0a12d229 b
367 diff -r 9161b9aeaf16 -r d89b0a12d229 b
368 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
368 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
369 +++ b/b Thu Jan 01 00:00:02 1970 +0000
369 +++ b/b Thu Jan 01 00:00:02 1970 +0000
370 @@ -0,0 +1,1 @@
370 @@ -0,0 +1,1 @@
371 +a
371 +a
372 diff -r 9161b9aeaf16 -r d89b0a12d229 g
372 diff -r 9161b9aeaf16 -r d89b0a12d229 g
373 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
373 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
374 +++ b/g Thu Jan 01 00:00:02 1970 +0000
374 +++ b/g Thu Jan 01 00:00:02 1970 +0000
375 @@ -0,0 +1,1 @@
375 @@ -0,0 +1,1 @@
376 +f
376 +f
377
377
378 changeset: 0:9161b9aeaf16
378 changeset: 0:9161b9aeaf16
379 user: test
379 user: test
380 date: Thu Jan 01 00:00:01 1970 +0000
380 date: Thu Jan 01 00:00:01 1970 +0000
381 summary: a
381 summary: a
382
382
383 diff -r 000000000000 -r 9161b9aeaf16 a
383 diff -r 000000000000 -r 9161b9aeaf16 a
384 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
384 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
385 +++ b/a Thu Jan 01 00:00:01 1970 +0000
385 +++ b/a Thu Jan 01 00:00:01 1970 +0000
386 @@ -0,0 +1,1 @@
386 @@ -0,0 +1,1 @@
387 +a
387 +a
388 diff -r 000000000000 -r 9161b9aeaf16 f
388 diff -r 000000000000 -r 9161b9aeaf16 f
389 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
389 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
390 +++ b/f Thu Jan 01 00:00:01 1970 +0000
390 +++ b/f Thu Jan 01 00:00:01 1970 +0000
391 @@ -0,0 +1,1 @@
391 @@ -0,0 +1,1 @@
392 +f
392 +f
393
393
394
394
395 log -vf dir/b
395 log -vf dir/b
396
396
397 $ hg log -vf dir/b
397 $ hg log -vf dir/b
398 changeset: 2:f8954cd4dc1f
398 changeset: 2:f8954cd4dc1f
399 user: test
399 user: test
400 date: Thu Jan 01 00:00:03 1970 +0000
400 date: Thu Jan 01 00:00:03 1970 +0000
401 files: b dir/b f g
401 files: b dir/b f g
402 description:
402 description:
403 c
403 c
404
404
405
405
406 changeset: 1:d89b0a12d229
406 changeset: 1:d89b0a12d229
407 user: test
407 user: test
408 date: Thu Jan 01 00:00:02 1970 +0000
408 date: Thu Jan 01 00:00:02 1970 +0000
409 files: b g
409 files: b g
410 description:
410 description:
411 b
411 b
412
412
413
413
414 changeset: 0:9161b9aeaf16
414 changeset: 0:9161b9aeaf16
415 user: test
415 user: test
416 date: Thu Jan 01 00:00:01 1970 +0000
416 date: Thu Jan 01 00:00:01 1970 +0000
417 files: a f
417 files: a f
418 description:
418 description:
419 a
419 a
420
420
421
421
422
422
423
423
424 -f and multiple filelog heads
424 -f and multiple filelog heads
425
425
426 $ hg up -q 2
426 $ hg up -q 2
427 $ hg log -f g --template '{rev}\n'
427 $ hg log -f g --template '{rev}\n'
428 2
428 2
429 1
429 1
430 0
430 0
431 $ hg up -q tip
431 $ hg up -q tip
432 $ hg log -f g --template '{rev}\n'
432 $ hg log -f g --template '{rev}\n'
433 3
433 3
434 2
434 2
435 0
435 0
436
436
437
437
438 log copies with --copies
438 log copies with --copies
439
439
440 $ hg log -vC --template '{rev} {file_copies}\n'
440 $ hg log -vC --template '{rev} {file_copies}\n'
441 4 e (dir/b)
441 4 e (dir/b)
442 3 b (a)g (f)
442 3 b (a)g (f)
443 2 dir/b (b)
443 2 dir/b (b)
444 1 b (a)g (f)
444 1 b (a)g (f)
445 0
445 0
446
446
447 log copies switch without --copies, with old filecopy template
447 log copies switch without --copies, with old filecopy template
448
448
449 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
449 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
450 4
450 4
451 3
451 3
452 2
452 2
453 1
453 1
454 0
454 0
455
455
456 log copies switch with --copies
456 log copies switch with --copies
457
457
458 $ hg log -vC --template '{rev} {file_copies_switch}\n'
458 $ hg log -vC --template '{rev} {file_copies_switch}\n'
459 4 e (dir/b)
459 4 e (dir/b)
460 3 b (a)g (f)
460 3 b (a)g (f)
461 2 dir/b (b)
461 2 dir/b (b)
462 1 b (a)g (f)
462 1 b (a)g (f)
463 0
463 0
464
464
465
465
466 log copies with hardcoded style and with --style=default
466 log copies with hardcoded style and with --style=default
467
467
468 $ hg log -vC -r4
468 $ hg log -vC -r4
469 changeset: 4:7e4639b4691b
469 changeset: 4:7e4639b4691b
470 tag: tip
470 tag: tip
471 user: test
471 user: test
472 date: Thu Jan 01 00:00:05 1970 +0000
472 date: Thu Jan 01 00:00:05 1970 +0000
473 files: dir/b e
473 files: dir/b e
474 copies: e (dir/b)
474 copies: e (dir/b)
475 description:
475 description:
476 e
476 e
477
477
478
478
479 $ hg log -vC -r4 --style=default
479 $ hg log -vC -r4 --style=default
480 changeset: 4:7e4639b4691b
480 changeset: 4:7e4639b4691b
481 tag: tip
481 tag: tip
482 user: test
482 user: test
483 date: Thu Jan 01 00:00:05 1970 +0000
483 date: Thu Jan 01 00:00:05 1970 +0000
484 files: dir/b e
484 files: dir/b e
485 copies: e (dir/b)
485 copies: e (dir/b)
486 description:
486 description:
487 e
487 e
488
488
489
489
490
490
491
491
492 log copies, non-linear manifest
492 log copies, non-linear manifest
493
493
494 $ hg up -C 3
494 $ hg up -C 3
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
496 $ hg mv dir/b e
496 $ hg mv dir/b e
497 $ echo foo > foo
497 $ echo foo > foo
498 $ hg ci -Ame2 -d '6 0'
498 $ hg ci -Ame2 -d '6 0'
499 adding foo
499 adding foo
500 created new head
500 created new head
501 $ hg log -v --template '{rev} {file_copies}\n' -r 5
501 $ hg log -v --template '{rev} {file_copies}\n' -r 5
502 5 e (dir/b)
502 5 e (dir/b)
503
503
504
504
505 log copies, execute bit set
505 log copies, execute bit set
506
506
507 #if execbit
507 #if execbit
508 $ chmod +x e
508 $ chmod +x e
509 $ hg ci -me3 -d '7 0'
509 $ hg ci -me3 -d '7 0'
510 $ hg log -v --template '{rev} {file_copies}\n' -r 6
510 $ hg log -v --template '{rev} {file_copies}\n' -r 6
511 6
511 6
512 #endif
512 #endif
513
513
514
514
515 log -p d
515 log -p d
516
516
517 $ hg log -pv d
517 $ hg log -pv d
518 changeset: 3:2ca5ba701980
518 changeset: 3:2ca5ba701980
519 user: test
519 user: test
520 date: Thu Jan 01 00:00:04 1970 +0000
520 date: Thu Jan 01 00:00:04 1970 +0000
521 files: a b d g
521 files: a b d g
522 description:
522 description:
523 d
523 d
524
524
525
525
526 diff -r f8954cd4dc1f -r 2ca5ba701980 d
526 diff -r f8954cd4dc1f -r 2ca5ba701980 d
527 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
527 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
528 +++ b/d Thu Jan 01 00:00:04 1970 +0000
528 +++ b/d Thu Jan 01 00:00:04 1970 +0000
529 @@ -0,0 +1,1 @@
529 @@ -0,0 +1,1 @@
530 +a
530 +a
531
531
532
532
533
533
534 log --removed file
534 log --removed file
535
535
536 $ hg log --removed -v a
536 $ hg log --removed -v a
537 changeset: 3:2ca5ba701980
537 changeset: 3:2ca5ba701980
538 user: test
538 user: test
539 date: Thu Jan 01 00:00:04 1970 +0000
539 date: Thu Jan 01 00:00:04 1970 +0000
540 files: a b d g
540 files: a b d g
541 description:
541 description:
542 d
542 d
543
543
544
544
545 changeset: 0:9161b9aeaf16
545 changeset: 0:9161b9aeaf16
546 user: test
546 user: test
547 date: Thu Jan 01 00:00:01 1970 +0000
547 date: Thu Jan 01 00:00:01 1970 +0000
548 files: a f
548 files: a f
549 description:
549 description:
550 a
550 a
551
551
552
552
553
553
554 log --removed revrange file
554 log --removed revrange file
555
555
556 $ hg log --removed -v -r0:2 a
556 $ hg log --removed -v -r0:2 a
557 changeset: 0:9161b9aeaf16
557 changeset: 0:9161b9aeaf16
558 user: test
558 user: test
559 date: Thu Jan 01 00:00:01 1970 +0000
559 date: Thu Jan 01 00:00:01 1970 +0000
560 files: a f
560 files: a f
561 description:
561 description:
562 a
562 a
563
563
564
564
565 $ cd ..
565 $ cd ..
566
566
567 log --follow tests
567 log --follow tests
568
568
569 $ hg init follow
569 $ hg init follow
570 $ cd follow
570 $ cd follow
571
571
572 $ echo base > base
572 $ echo base > base
573 $ hg ci -Ambase -d '1 0'
573 $ hg ci -Ambase -d '1 0'
574 adding base
574 adding base
575
575
576 $ echo r1 >> base
576 $ echo r1 >> base
577 $ hg ci -Amr1 -d '1 0'
577 $ hg ci -Amr1 -d '1 0'
578 $ echo r2 >> base
578 $ echo r2 >> base
579 $ hg ci -Amr2 -d '1 0'
579 $ hg ci -Amr2 -d '1 0'
580
580
581 $ hg up -C 1
581 $ hg up -C 1
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 $ echo b1 > b1
583 $ echo b1 > b1
584 $ hg ci -Amb1 -d '1 0'
584 $ hg ci -Amb1 -d '1 0'
585 adding b1
585 adding b1
586 created new head
586 created new head
587
587
588
588
589 log -f
589 log -f
590
590
591 $ hg log -f
591 $ hg log -f
592 changeset: 3:e62f78d544b4
592 changeset: 3:e62f78d544b4
593 tag: tip
593 tag: tip
594 parent: 1:3d5bf5654eda
594 parent: 1:3d5bf5654eda
595 user: test
595 user: test
596 date: Thu Jan 01 00:00:01 1970 +0000
596 date: Thu Jan 01 00:00:01 1970 +0000
597 summary: b1
597 summary: b1
598
598
599 changeset: 1:3d5bf5654eda
599 changeset: 1:3d5bf5654eda
600 user: test
600 user: test
601 date: Thu Jan 01 00:00:01 1970 +0000
601 date: Thu Jan 01 00:00:01 1970 +0000
602 summary: r1
602 summary: r1
603
603
604 changeset: 0:67e992f2c4f3
604 changeset: 0:67e992f2c4f3
605 user: test
605 user: test
606 date: Thu Jan 01 00:00:01 1970 +0000
606 date: Thu Jan 01 00:00:01 1970 +0000
607 summary: base
607 summary: base
608
608
609
609
610
610
611 log -f -r 1:tip
611 log -f -r 1:tip
612
612
613 $ hg up -C 0
613 $ hg up -C 0
614 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
614 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
615 $ echo b2 > b2
615 $ echo b2 > b2
616 $ hg ci -Amb2 -d '1 0'
616 $ hg ci -Amb2 -d '1 0'
617 adding b2
617 adding b2
618 created new head
618 created new head
619 $ hg log -f -r 1:tip
619 $ hg log -f -r 1:tip
620 changeset: 1:3d5bf5654eda
620 changeset: 1:3d5bf5654eda
621 user: test
621 user: test
622 date: Thu Jan 01 00:00:01 1970 +0000
622 date: Thu Jan 01 00:00:01 1970 +0000
623 summary: r1
623 summary: r1
624
624
625 changeset: 2:60c670bf5b30
625 changeset: 2:60c670bf5b30
626 user: test
626 user: test
627 date: Thu Jan 01 00:00:01 1970 +0000
627 date: Thu Jan 01 00:00:01 1970 +0000
628 summary: r2
628 summary: r2
629
629
630 changeset: 3:e62f78d544b4
630 changeset: 3:e62f78d544b4
631 parent: 1:3d5bf5654eda
631 parent: 1:3d5bf5654eda
632 user: test
632 user: test
633 date: Thu Jan 01 00:00:01 1970 +0000
633 date: Thu Jan 01 00:00:01 1970 +0000
634 summary: b1
634 summary: b1
635
635
636
636
637
637
638 log -f -r null
639
640 $ hg log -f -r null
641 changeset: -1:000000000000
642 user:
643 date: Thu Jan 01 00:00:00 1970 +0000
644
645 $ hg log -f -r null -G
646 o changeset: -1:000000000000
647 user:
648 date: Thu Jan 01 00:00:00 1970 +0000
649
650
651
638 log -r . with two parents
652 log -r . with two parents
639
653
640 $ hg up -C 3
654 $ hg up -C 3
641 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
655 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
642 $ hg merge tip
656 $ hg merge tip
643 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
657 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
644 (branch merge, don't forget to commit)
658 (branch merge, don't forget to commit)
645 $ hg log -r .
659 $ hg log -r .
646 changeset: 3:e62f78d544b4
660 changeset: 3:e62f78d544b4
647 parent: 1:3d5bf5654eda
661 parent: 1:3d5bf5654eda
648 user: test
662 user: test
649 date: Thu Jan 01 00:00:01 1970 +0000
663 date: Thu Jan 01 00:00:01 1970 +0000
650 summary: b1
664 summary: b1
651
665
652
666
653
667
654 log -r . with one parent
668 log -r . with one parent
655
669
656 $ hg ci -mm12 -d '1 0'
670 $ hg ci -mm12 -d '1 0'
657 $ hg log -r .
671 $ hg log -r .
658 changeset: 5:302e9dd6890d
672 changeset: 5:302e9dd6890d
659 tag: tip
673 tag: tip
660 parent: 3:e62f78d544b4
674 parent: 3:e62f78d544b4
661 parent: 4:ddb82e70d1a1
675 parent: 4:ddb82e70d1a1
662 user: test
676 user: test
663 date: Thu Jan 01 00:00:01 1970 +0000
677 date: Thu Jan 01 00:00:01 1970 +0000
664 summary: m12
678 summary: m12
665
679
666
680
667 $ echo postm >> b1
681 $ echo postm >> b1
668 $ hg ci -Amb1.1 -d'1 0'
682 $ hg ci -Amb1.1 -d'1 0'
669
683
670
684
671 log --follow-first
685 log --follow-first
672
686
673 $ hg log --follow-first
687 $ hg log --follow-first
674 changeset: 6:2404bbcab562
688 changeset: 6:2404bbcab562
675 tag: tip
689 tag: tip
676 user: test
690 user: test
677 date: Thu Jan 01 00:00:01 1970 +0000
691 date: Thu Jan 01 00:00:01 1970 +0000
678 summary: b1.1
692 summary: b1.1
679
693
680 changeset: 5:302e9dd6890d
694 changeset: 5:302e9dd6890d
681 parent: 3:e62f78d544b4
695 parent: 3:e62f78d544b4
682 parent: 4:ddb82e70d1a1
696 parent: 4:ddb82e70d1a1
683 user: test
697 user: test
684 date: Thu Jan 01 00:00:01 1970 +0000
698 date: Thu Jan 01 00:00:01 1970 +0000
685 summary: m12
699 summary: m12
686
700
687 changeset: 3:e62f78d544b4
701 changeset: 3:e62f78d544b4
688 parent: 1:3d5bf5654eda
702 parent: 1:3d5bf5654eda
689 user: test
703 user: test
690 date: Thu Jan 01 00:00:01 1970 +0000
704 date: Thu Jan 01 00:00:01 1970 +0000
691 summary: b1
705 summary: b1
692
706
693 changeset: 1:3d5bf5654eda
707 changeset: 1:3d5bf5654eda
694 user: test
708 user: test
695 date: Thu Jan 01 00:00:01 1970 +0000
709 date: Thu Jan 01 00:00:01 1970 +0000
696 summary: r1
710 summary: r1
697
711
698 changeset: 0:67e992f2c4f3
712 changeset: 0:67e992f2c4f3
699 user: test
713 user: test
700 date: Thu Jan 01 00:00:01 1970 +0000
714 date: Thu Jan 01 00:00:01 1970 +0000
701 summary: base
715 summary: base
702
716
703
717
704
718
705 log -P 2
719 log -P 2
706
720
707 $ hg log -P 2
721 $ hg log -P 2
708 changeset: 6:2404bbcab562
722 changeset: 6:2404bbcab562
709 tag: tip
723 tag: tip
710 user: test
724 user: test
711 date: Thu Jan 01 00:00:01 1970 +0000
725 date: Thu Jan 01 00:00:01 1970 +0000
712 summary: b1.1
726 summary: b1.1
713
727
714 changeset: 5:302e9dd6890d
728 changeset: 5:302e9dd6890d
715 parent: 3:e62f78d544b4
729 parent: 3:e62f78d544b4
716 parent: 4:ddb82e70d1a1
730 parent: 4:ddb82e70d1a1
717 user: test
731 user: test
718 date: Thu Jan 01 00:00:01 1970 +0000
732 date: Thu Jan 01 00:00:01 1970 +0000
719 summary: m12
733 summary: m12
720
734
721 changeset: 4:ddb82e70d1a1
735 changeset: 4:ddb82e70d1a1
722 parent: 0:67e992f2c4f3
736 parent: 0:67e992f2c4f3
723 user: test
737 user: test
724 date: Thu Jan 01 00:00:01 1970 +0000
738 date: Thu Jan 01 00:00:01 1970 +0000
725 summary: b2
739 summary: b2
726
740
727 changeset: 3:e62f78d544b4
741 changeset: 3:e62f78d544b4
728 parent: 1:3d5bf5654eda
742 parent: 1:3d5bf5654eda
729 user: test
743 user: test
730 date: Thu Jan 01 00:00:01 1970 +0000
744 date: Thu Jan 01 00:00:01 1970 +0000
731 summary: b1
745 summary: b1
732
746
733
747
734
748
735 log -r tip -p --git
749 log -r tip -p --git
736
750
737 $ hg log -r tip -p --git
751 $ hg log -r tip -p --git
738 changeset: 6:2404bbcab562
752 changeset: 6:2404bbcab562
739 tag: tip
753 tag: tip
740 user: test
754 user: test
741 date: Thu Jan 01 00:00:01 1970 +0000
755 date: Thu Jan 01 00:00:01 1970 +0000
742 summary: b1.1
756 summary: b1.1
743
757
744 diff --git a/b1 b/b1
758 diff --git a/b1 b/b1
745 --- a/b1
759 --- a/b1
746 +++ b/b1
760 +++ b/b1
747 @@ -1,1 +1,2 @@
761 @@ -1,1 +1,2 @@
748 b1
762 b1
749 +postm
763 +postm
750
764
751
765
752
766
753 log -r ""
767 log -r ""
754
768
755 $ hg log -r ''
769 $ hg log -r ''
756 hg: parse error: empty query
770 hg: parse error: empty query
757 [255]
771 [255]
758
772
759 log -r <some unknown node id>
773 log -r <some unknown node id>
760
774
761 $ hg log -r 1000000000000000000000000000000000000000
775 $ hg log -r 1000000000000000000000000000000000000000
762 abort: unknown revision '1000000000000000000000000000000000000000'!
776 abort: unknown revision '1000000000000000000000000000000000000000'!
763 [255]
777 [255]
764
778
765 log -k r1
779 log -k r1
766
780
767 $ hg log -k r1
781 $ hg log -k r1
768 changeset: 1:3d5bf5654eda
782 changeset: 1:3d5bf5654eda
769 user: test
783 user: test
770 date: Thu Jan 01 00:00:01 1970 +0000
784 date: Thu Jan 01 00:00:01 1970 +0000
771 summary: r1
785 summary: r1
772
786
773 log -p -l2 --color=always
787 log -p -l2 --color=always
774
788
775 $ hg --config extensions.color= --config color.mode=ansi \
789 $ hg --config extensions.color= --config color.mode=ansi \
776 > log -p -l2 --color=always
790 > log -p -l2 --color=always
777 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
791 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
778 tag: tip
792 tag: tip
779 user: test
793 user: test
780 date: Thu Jan 01 00:00:01 1970 +0000
794 date: Thu Jan 01 00:00:01 1970 +0000
781 summary: b1.1
795 summary: b1.1
782
796
783 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
797 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
784 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
798 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
785 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
799 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
786 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
800 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
787 b1
801 b1
788 \x1b[0;32m+postm\x1b[0m (esc)
802 \x1b[0;32m+postm\x1b[0m (esc)
789
803
790 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
804 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
791 parent: 3:e62f78d544b4
805 parent: 3:e62f78d544b4
792 parent: 4:ddb82e70d1a1
806 parent: 4:ddb82e70d1a1
793 user: test
807 user: test
794 date: Thu Jan 01 00:00:01 1970 +0000
808 date: Thu Jan 01 00:00:01 1970 +0000
795 summary: m12
809 summary: m12
796
810
797 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
811 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
798 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
812 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
799 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
813 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
800 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
814 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
801 \x1b[0;32m+b2\x1b[0m (esc)
815 \x1b[0;32m+b2\x1b[0m (esc)
802
816
803
817
804
818
805 log -r tip --stat
819 log -r tip --stat
806
820
807 $ hg log -r tip --stat
821 $ hg log -r tip --stat
808 changeset: 6:2404bbcab562
822 changeset: 6:2404bbcab562
809 tag: tip
823 tag: tip
810 user: test
824 user: test
811 date: Thu Jan 01 00:00:01 1970 +0000
825 date: Thu Jan 01 00:00:01 1970 +0000
812 summary: b1.1
826 summary: b1.1
813
827
814 b1 | 1 +
828 b1 | 1 +
815 1 files changed, 1 insertions(+), 0 deletions(-)
829 1 files changed, 1 insertions(+), 0 deletions(-)
816
830
817
831
818 $ cd ..
832 $ cd ..
819
833
820
834
821 User
835 User
822
836
823 $ hg init usertest
837 $ hg init usertest
824 $ cd usertest
838 $ cd usertest
825
839
826 $ echo a > a
840 $ echo a > a
827 $ hg ci -A -m "a" -u "User One <user1@example.org>"
841 $ hg ci -A -m "a" -u "User One <user1@example.org>"
828 adding a
842 adding a
829 $ echo b > b
843 $ echo b > b
830 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
844 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
831 adding b
845 adding b
832
846
833 $ hg log -u "User One <user1@example.org>"
847 $ hg log -u "User One <user1@example.org>"
834 changeset: 0:29a4c94f1924
848 changeset: 0:29a4c94f1924
835 user: User One <user1@example.org>
849 user: User One <user1@example.org>
836 date: Thu Jan 01 00:00:00 1970 +0000
850 date: Thu Jan 01 00:00:00 1970 +0000
837 summary: a
851 summary: a
838
852
839 $ hg log -u "user1" -u "user2"
853 $ hg log -u "user1" -u "user2"
840 changeset: 1:e834b5e69c0e
854 changeset: 1:e834b5e69c0e
841 tag: tip
855 tag: tip
842 user: User Two <user2@example.org>
856 user: User Two <user2@example.org>
843 date: Thu Jan 01 00:00:00 1970 +0000
857 date: Thu Jan 01 00:00:00 1970 +0000
844 summary: b
858 summary: b
845
859
846 changeset: 0:29a4c94f1924
860 changeset: 0:29a4c94f1924
847 user: User One <user1@example.org>
861 user: User One <user1@example.org>
848 date: Thu Jan 01 00:00:00 1970 +0000
862 date: Thu Jan 01 00:00:00 1970 +0000
849 summary: a
863 summary: a
850
864
851 $ hg log -u "user3"
865 $ hg log -u "user3"
852
866
853 $ cd ..
867 $ cd ..
854
868
855 $ hg init branches
869 $ hg init branches
856 $ cd branches
870 $ cd branches
857
871
858 $ echo a > a
872 $ echo a > a
859 $ hg ci -A -m "commit on default"
873 $ hg ci -A -m "commit on default"
860 adding a
874 adding a
861 $ hg branch test
875 $ hg branch test
862 marked working directory as branch test
876 marked working directory as branch test
863 (branches are permanent and global, did you want a bookmark?)
877 (branches are permanent and global, did you want a bookmark?)
864 $ echo b > b
878 $ echo b > b
865 $ hg ci -A -m "commit on test"
879 $ hg ci -A -m "commit on test"
866 adding b
880 adding b
867
881
868 $ hg up default
882 $ hg up default
869 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
883 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
870 $ echo c > c
884 $ echo c > c
871 $ hg ci -A -m "commit on default"
885 $ hg ci -A -m "commit on default"
872 adding c
886 adding c
873 $ hg up test
887 $ hg up test
874 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
888 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
875 $ echo c > c
889 $ echo c > c
876 $ hg ci -A -m "commit on test"
890 $ hg ci -A -m "commit on test"
877 adding c
891 adding c
878
892
879
893
880 log -b default
894 log -b default
881
895
882 $ hg log -b default
896 $ hg log -b default
883 changeset: 2:c3a4f03cc9a7
897 changeset: 2:c3a4f03cc9a7
884 parent: 0:24427303d56f
898 parent: 0:24427303d56f
885 user: test
899 user: test
886 date: Thu Jan 01 00:00:00 1970 +0000
900 date: Thu Jan 01 00:00:00 1970 +0000
887 summary: commit on default
901 summary: commit on default
888
902
889 changeset: 0:24427303d56f
903 changeset: 0:24427303d56f
890 user: test
904 user: test
891 date: Thu Jan 01 00:00:00 1970 +0000
905 date: Thu Jan 01 00:00:00 1970 +0000
892 summary: commit on default
906 summary: commit on default
893
907
894
908
895
909
896 log -b test
910 log -b test
897
911
898 $ hg log -b test
912 $ hg log -b test
899 changeset: 3:f5d8de11c2e2
913 changeset: 3:f5d8de11c2e2
900 branch: test
914 branch: test
901 tag: tip
915 tag: tip
902 parent: 1:d32277701ccb
916 parent: 1:d32277701ccb
903 user: test
917 user: test
904 date: Thu Jan 01 00:00:00 1970 +0000
918 date: Thu Jan 01 00:00:00 1970 +0000
905 summary: commit on test
919 summary: commit on test
906
920
907 changeset: 1:d32277701ccb
921 changeset: 1:d32277701ccb
908 branch: test
922 branch: test
909 user: test
923 user: test
910 date: Thu Jan 01 00:00:00 1970 +0000
924 date: Thu Jan 01 00:00:00 1970 +0000
911 summary: commit on test
925 summary: commit on test
912
926
913
927
914
928
915 log -b dummy
929 log -b dummy
916
930
917 $ hg log -b dummy
931 $ hg log -b dummy
918 abort: unknown revision 'dummy'!
932 abort: unknown revision 'dummy'!
919 [255]
933 [255]
920
934
921
935
922 log -b .
936 log -b .
923
937
924 $ hg log -b .
938 $ hg log -b .
925 changeset: 3:f5d8de11c2e2
939 changeset: 3:f5d8de11c2e2
926 branch: test
940 branch: test
927 tag: tip
941 tag: tip
928 parent: 1:d32277701ccb
942 parent: 1:d32277701ccb
929 user: test
943 user: test
930 date: Thu Jan 01 00:00:00 1970 +0000
944 date: Thu Jan 01 00:00:00 1970 +0000
931 summary: commit on test
945 summary: commit on test
932
946
933 changeset: 1:d32277701ccb
947 changeset: 1:d32277701ccb
934 branch: test
948 branch: test
935 user: test
949 user: test
936 date: Thu Jan 01 00:00:00 1970 +0000
950 date: Thu Jan 01 00:00:00 1970 +0000
937 summary: commit on test
951 summary: commit on test
938
952
939
953
940
954
941 log -b default -b test
955 log -b default -b test
942
956
943 $ hg log -b default -b test
957 $ hg log -b default -b test
944 changeset: 3:f5d8de11c2e2
958 changeset: 3:f5d8de11c2e2
945 branch: test
959 branch: test
946 tag: tip
960 tag: tip
947 parent: 1:d32277701ccb
961 parent: 1:d32277701ccb
948 user: test
962 user: test
949 date: Thu Jan 01 00:00:00 1970 +0000
963 date: Thu Jan 01 00:00:00 1970 +0000
950 summary: commit on test
964 summary: commit on test
951
965
952 changeset: 2:c3a4f03cc9a7
966 changeset: 2:c3a4f03cc9a7
953 parent: 0:24427303d56f
967 parent: 0:24427303d56f
954 user: test
968 user: test
955 date: Thu Jan 01 00:00:00 1970 +0000
969 date: Thu Jan 01 00:00:00 1970 +0000
956 summary: commit on default
970 summary: commit on default
957
971
958 changeset: 1:d32277701ccb
972 changeset: 1:d32277701ccb
959 branch: test
973 branch: test
960 user: test
974 user: test
961 date: Thu Jan 01 00:00:00 1970 +0000
975 date: Thu Jan 01 00:00:00 1970 +0000
962 summary: commit on test
976 summary: commit on test
963
977
964 changeset: 0:24427303d56f
978 changeset: 0:24427303d56f
965 user: test
979 user: test
966 date: Thu Jan 01 00:00:00 1970 +0000
980 date: Thu Jan 01 00:00:00 1970 +0000
967 summary: commit on default
981 summary: commit on default
968
982
969
983
970
984
971 log -b default -b .
985 log -b default -b .
972
986
973 $ hg log -b default -b .
987 $ hg log -b default -b .
974 changeset: 3:f5d8de11c2e2
988 changeset: 3:f5d8de11c2e2
975 branch: test
989 branch: test
976 tag: tip
990 tag: tip
977 parent: 1:d32277701ccb
991 parent: 1:d32277701ccb
978 user: test
992 user: test
979 date: Thu Jan 01 00:00:00 1970 +0000
993 date: Thu Jan 01 00:00:00 1970 +0000
980 summary: commit on test
994 summary: commit on test
981
995
982 changeset: 2:c3a4f03cc9a7
996 changeset: 2:c3a4f03cc9a7
983 parent: 0:24427303d56f
997 parent: 0:24427303d56f
984 user: test
998 user: test
985 date: Thu Jan 01 00:00:00 1970 +0000
999 date: Thu Jan 01 00:00:00 1970 +0000
986 summary: commit on default
1000 summary: commit on default
987
1001
988 changeset: 1:d32277701ccb
1002 changeset: 1:d32277701ccb
989 branch: test
1003 branch: test
990 user: test
1004 user: test
991 date: Thu Jan 01 00:00:00 1970 +0000
1005 date: Thu Jan 01 00:00:00 1970 +0000
992 summary: commit on test
1006 summary: commit on test
993
1007
994 changeset: 0:24427303d56f
1008 changeset: 0:24427303d56f
995 user: test
1009 user: test
996 date: Thu Jan 01 00:00:00 1970 +0000
1010 date: Thu Jan 01 00:00:00 1970 +0000
997 summary: commit on default
1011 summary: commit on default
998
1012
999
1013
1000
1014
1001 log -b . -b test
1015 log -b . -b test
1002
1016
1003 $ hg log -b . -b test
1017 $ hg log -b . -b test
1004 changeset: 3:f5d8de11c2e2
1018 changeset: 3:f5d8de11c2e2
1005 branch: test
1019 branch: test
1006 tag: tip
1020 tag: tip
1007 parent: 1:d32277701ccb
1021 parent: 1:d32277701ccb
1008 user: test
1022 user: test
1009 date: Thu Jan 01 00:00:00 1970 +0000
1023 date: Thu Jan 01 00:00:00 1970 +0000
1010 summary: commit on test
1024 summary: commit on test
1011
1025
1012 changeset: 1:d32277701ccb
1026 changeset: 1:d32277701ccb
1013 branch: test
1027 branch: test
1014 user: test
1028 user: test
1015 date: Thu Jan 01 00:00:00 1970 +0000
1029 date: Thu Jan 01 00:00:00 1970 +0000
1016 summary: commit on test
1030 summary: commit on test
1017
1031
1018
1032
1019
1033
1020 log -b 2
1034 log -b 2
1021
1035
1022 $ hg log -b 2
1036 $ hg log -b 2
1023 changeset: 2:c3a4f03cc9a7
1037 changeset: 2:c3a4f03cc9a7
1024 parent: 0:24427303d56f
1038 parent: 0:24427303d56f
1025 user: test
1039 user: test
1026 date: Thu Jan 01 00:00:00 1970 +0000
1040 date: Thu Jan 01 00:00:00 1970 +0000
1027 summary: commit on default
1041 summary: commit on default
1028
1042
1029 changeset: 0:24427303d56f
1043 changeset: 0:24427303d56f
1030 user: test
1044 user: test
1031 date: Thu Jan 01 00:00:00 1970 +0000
1045 date: Thu Jan 01 00:00:00 1970 +0000
1032 summary: commit on default
1046 summary: commit on default
1033
1047
1034 #if gettext
1048 #if gettext
1035
1049
1036 Test that all log names are translated (e.g. branches, bookmarks, tags):
1050 Test that all log names are translated (e.g. branches, bookmarks, tags):
1037
1051
1038 $ hg bookmark babar -r tip
1052 $ hg bookmark babar -r tip
1039
1053
1040 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1054 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1041 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1055 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1042 Zweig: test
1056 Zweig: test
1043 Lesezeichen: babar
1057 Lesezeichen: babar
1044 Marke: tip
1058 Marke: tip
1045 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1059 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1046 Nutzer: test
1060 Nutzer: test
1047 Datum: Thu Jan 01 00:00:00 1970 +0000
1061 Datum: Thu Jan 01 00:00:00 1970 +0000
1048 Zusammenfassung: commit on test
1062 Zusammenfassung: commit on test
1049
1063
1050 $ hg bookmark -d babar
1064 $ hg bookmark -d babar
1051
1065
1052 #endif
1066 #endif
1053
1067
1054 log -p --cwd dir (in subdir)
1068 log -p --cwd dir (in subdir)
1055
1069
1056 $ mkdir dir
1070 $ mkdir dir
1057 $ hg log -p --cwd dir
1071 $ hg log -p --cwd dir
1058 changeset: 3:f5d8de11c2e2
1072 changeset: 3:f5d8de11c2e2
1059 branch: test
1073 branch: test
1060 tag: tip
1074 tag: tip
1061 parent: 1:d32277701ccb
1075 parent: 1:d32277701ccb
1062 user: test
1076 user: test
1063 date: Thu Jan 01 00:00:00 1970 +0000
1077 date: Thu Jan 01 00:00:00 1970 +0000
1064 summary: commit on test
1078 summary: commit on test
1065
1079
1066 diff -r d32277701ccb -r f5d8de11c2e2 c
1080 diff -r d32277701ccb -r f5d8de11c2e2 c
1067 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1081 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1068 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1082 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1069 @@ -0,0 +1,1 @@
1083 @@ -0,0 +1,1 @@
1070 +c
1084 +c
1071
1085
1072 changeset: 2:c3a4f03cc9a7
1086 changeset: 2:c3a4f03cc9a7
1073 parent: 0:24427303d56f
1087 parent: 0:24427303d56f
1074 user: test
1088 user: test
1075 date: Thu Jan 01 00:00:00 1970 +0000
1089 date: Thu Jan 01 00:00:00 1970 +0000
1076 summary: commit on default
1090 summary: commit on default
1077
1091
1078 diff -r 24427303d56f -r c3a4f03cc9a7 c
1092 diff -r 24427303d56f -r c3a4f03cc9a7 c
1079 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1093 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1080 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1094 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1081 @@ -0,0 +1,1 @@
1095 @@ -0,0 +1,1 @@
1082 +c
1096 +c
1083
1097
1084 changeset: 1:d32277701ccb
1098 changeset: 1:d32277701ccb
1085 branch: test
1099 branch: test
1086 user: test
1100 user: test
1087 date: Thu Jan 01 00:00:00 1970 +0000
1101 date: Thu Jan 01 00:00:00 1970 +0000
1088 summary: commit on test
1102 summary: commit on test
1089
1103
1090 diff -r 24427303d56f -r d32277701ccb b
1104 diff -r 24427303d56f -r d32277701ccb b
1091 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1105 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1092 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1106 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1093 @@ -0,0 +1,1 @@
1107 @@ -0,0 +1,1 @@
1094 +b
1108 +b
1095
1109
1096 changeset: 0:24427303d56f
1110 changeset: 0:24427303d56f
1097 user: test
1111 user: test
1098 date: Thu Jan 01 00:00:00 1970 +0000
1112 date: Thu Jan 01 00:00:00 1970 +0000
1099 summary: commit on default
1113 summary: commit on default
1100
1114
1101 diff -r 000000000000 -r 24427303d56f a
1115 diff -r 000000000000 -r 24427303d56f a
1102 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1116 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1103 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1117 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1104 @@ -0,0 +1,1 @@
1118 @@ -0,0 +1,1 @@
1105 +a
1119 +a
1106
1120
1107
1121
1108
1122
1109 log -p -R repo
1123 log -p -R repo
1110
1124
1111 $ cd dir
1125 $ cd dir
1112 $ hg log -p -R .. ../a
1126 $ hg log -p -R .. ../a
1113 changeset: 0:24427303d56f
1127 changeset: 0:24427303d56f
1114 user: test
1128 user: test
1115 date: Thu Jan 01 00:00:00 1970 +0000
1129 date: Thu Jan 01 00:00:00 1970 +0000
1116 summary: commit on default
1130 summary: commit on default
1117
1131
1118 diff -r 000000000000 -r 24427303d56f a
1132 diff -r 000000000000 -r 24427303d56f a
1119 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1133 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1120 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1134 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1121 @@ -0,0 +1,1 @@
1135 @@ -0,0 +1,1 @@
1122 +a
1136 +a
1123
1137
1124
1138
1125 $ cd ../..
1139 $ cd ../..
1126
1140
1127 $ hg init follow2
1141 $ hg init follow2
1128 $ cd follow2
1142 $ cd follow2
1129
1143
1130 # Build the following history:
1144 # Build the following history:
1131 # tip - o - x - o - x - x
1145 # tip - o - x - o - x - x
1132 # \ /
1146 # \ /
1133 # o - o - o - x
1147 # o - o - o - x
1134 # \ /
1148 # \ /
1135 # o
1149 # o
1136 #
1150 #
1137 # Where "o" is a revision containing "foo" and
1151 # Where "o" is a revision containing "foo" and
1138 # "x" is a revision without "foo"
1152 # "x" is a revision without "foo"
1139
1153
1140 $ touch init
1154 $ touch init
1141 $ hg ci -A -m "init, unrelated"
1155 $ hg ci -A -m "init, unrelated"
1142 adding init
1156 adding init
1143 $ echo 'foo' > init
1157 $ echo 'foo' > init
1144 $ hg ci -m "change, unrelated"
1158 $ hg ci -m "change, unrelated"
1145 $ echo 'foo' > foo
1159 $ echo 'foo' > foo
1146 $ hg ci -A -m "add unrelated old foo"
1160 $ hg ci -A -m "add unrelated old foo"
1147 adding foo
1161 adding foo
1148 $ hg rm foo
1162 $ hg rm foo
1149 $ hg ci -m "delete foo, unrelated"
1163 $ hg ci -m "delete foo, unrelated"
1150 $ echo 'related' > foo
1164 $ echo 'related' > foo
1151 $ hg ci -A -m "add foo, related"
1165 $ hg ci -A -m "add foo, related"
1152 adding foo
1166 adding foo
1153
1167
1154 $ hg up 0
1168 $ hg up 0
1155 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1169 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1156 $ touch branch
1170 $ touch branch
1157 $ hg ci -A -m "first branch, unrelated"
1171 $ hg ci -A -m "first branch, unrelated"
1158 adding branch
1172 adding branch
1159 created new head
1173 created new head
1160 $ touch foo
1174 $ touch foo
1161 $ hg ci -A -m "create foo, related"
1175 $ hg ci -A -m "create foo, related"
1162 adding foo
1176 adding foo
1163 $ echo 'change' > foo
1177 $ echo 'change' > foo
1164 $ hg ci -m "change foo, related"
1178 $ hg ci -m "change foo, related"
1165
1179
1166 $ hg up 6
1180 $ hg up 6
1167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1181 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1168 $ echo 'change foo in branch' > foo
1182 $ echo 'change foo in branch' > foo
1169 $ hg ci -m "change foo in branch, related"
1183 $ hg ci -m "change foo in branch, related"
1170 created new head
1184 created new head
1171 $ hg merge 7
1185 $ hg merge 7
1172 merging foo
1186 merging foo
1173 warning: conflicts during merge.
1187 warning: conflicts during merge.
1174 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1188 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1175 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1189 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1176 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1190 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1177 [1]
1191 [1]
1178 $ echo 'merge 1' > foo
1192 $ echo 'merge 1' > foo
1179 $ hg resolve -m foo
1193 $ hg resolve -m foo
1180 (no more unresolved files)
1194 (no more unresolved files)
1181 $ hg ci -m "First merge, related"
1195 $ hg ci -m "First merge, related"
1182
1196
1183 $ hg merge 4
1197 $ hg merge 4
1184 merging foo
1198 merging foo
1185 warning: conflicts during merge.
1199 warning: conflicts during merge.
1186 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1200 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1187 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1201 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1188 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1202 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1189 [1]
1203 [1]
1190 $ echo 'merge 2' > foo
1204 $ echo 'merge 2' > foo
1191 $ hg resolve -m foo
1205 $ hg resolve -m foo
1192 (no more unresolved files)
1206 (no more unresolved files)
1193 $ hg ci -m "Last merge, related"
1207 $ hg ci -m "Last merge, related"
1194
1208
1195 $ hg log --graph
1209 $ hg log --graph
1196 @ changeset: 10:4dae8563d2c5
1210 @ changeset: 10:4dae8563d2c5
1197 |\ tag: tip
1211 |\ tag: tip
1198 | | parent: 9:7b35701b003e
1212 | | parent: 9:7b35701b003e
1199 | | parent: 4:88176d361b69
1213 | | parent: 4:88176d361b69
1200 | | user: test
1214 | | user: test
1201 | | date: Thu Jan 01 00:00:00 1970 +0000
1215 | | date: Thu Jan 01 00:00:00 1970 +0000
1202 | | summary: Last merge, related
1216 | | summary: Last merge, related
1203 | |
1217 | |
1204 | o changeset: 9:7b35701b003e
1218 | o changeset: 9:7b35701b003e
1205 | |\ parent: 8:e5416ad8a855
1219 | |\ parent: 8:e5416ad8a855
1206 | | | parent: 7:87fe3144dcfa
1220 | | | parent: 7:87fe3144dcfa
1207 | | | user: test
1221 | | | user: test
1208 | | | date: Thu Jan 01 00:00:00 1970 +0000
1222 | | | date: Thu Jan 01 00:00:00 1970 +0000
1209 | | | summary: First merge, related
1223 | | | summary: First merge, related
1210 | | |
1224 | | |
1211 | | o changeset: 8:e5416ad8a855
1225 | | o changeset: 8:e5416ad8a855
1212 | | | parent: 6:dc6c325fe5ee
1226 | | | parent: 6:dc6c325fe5ee
1213 | | | user: test
1227 | | | user: test
1214 | | | date: Thu Jan 01 00:00:00 1970 +0000
1228 | | | date: Thu Jan 01 00:00:00 1970 +0000
1215 | | | summary: change foo in branch, related
1229 | | | summary: change foo in branch, related
1216 | | |
1230 | | |
1217 | o | changeset: 7:87fe3144dcfa
1231 | o | changeset: 7:87fe3144dcfa
1218 | |/ user: test
1232 | |/ user: test
1219 | | date: Thu Jan 01 00:00:00 1970 +0000
1233 | | date: Thu Jan 01 00:00:00 1970 +0000
1220 | | summary: change foo, related
1234 | | summary: change foo, related
1221 | |
1235 | |
1222 | o changeset: 6:dc6c325fe5ee
1236 | o changeset: 6:dc6c325fe5ee
1223 | | user: test
1237 | | user: test
1224 | | date: Thu Jan 01 00:00:00 1970 +0000
1238 | | date: Thu Jan 01 00:00:00 1970 +0000
1225 | | summary: create foo, related
1239 | | summary: create foo, related
1226 | |
1240 | |
1227 | o changeset: 5:73db34516eb9
1241 | o changeset: 5:73db34516eb9
1228 | | parent: 0:e87515fd044a
1242 | | parent: 0:e87515fd044a
1229 | | user: test
1243 | | user: test
1230 | | date: Thu Jan 01 00:00:00 1970 +0000
1244 | | date: Thu Jan 01 00:00:00 1970 +0000
1231 | | summary: first branch, unrelated
1245 | | summary: first branch, unrelated
1232 | |
1246 | |
1233 o | changeset: 4:88176d361b69
1247 o | changeset: 4:88176d361b69
1234 | | user: test
1248 | | user: test
1235 | | date: Thu Jan 01 00:00:00 1970 +0000
1249 | | date: Thu Jan 01 00:00:00 1970 +0000
1236 | | summary: add foo, related
1250 | | summary: add foo, related
1237 | |
1251 | |
1238 o | changeset: 3:dd78ae4afb56
1252 o | changeset: 3:dd78ae4afb56
1239 | | user: test
1253 | | user: test
1240 | | date: Thu Jan 01 00:00:00 1970 +0000
1254 | | date: Thu Jan 01 00:00:00 1970 +0000
1241 | | summary: delete foo, unrelated
1255 | | summary: delete foo, unrelated
1242 | |
1256 | |
1243 o | changeset: 2:c4c64aedf0f7
1257 o | changeset: 2:c4c64aedf0f7
1244 | | user: test
1258 | | user: test
1245 | | date: Thu Jan 01 00:00:00 1970 +0000
1259 | | date: Thu Jan 01 00:00:00 1970 +0000
1246 | | summary: add unrelated old foo
1260 | | summary: add unrelated old foo
1247 | |
1261 | |
1248 o | changeset: 1:e5faa7440653
1262 o | changeset: 1:e5faa7440653
1249 |/ user: test
1263 |/ user: test
1250 | date: Thu Jan 01 00:00:00 1970 +0000
1264 | date: Thu Jan 01 00:00:00 1970 +0000
1251 | summary: change, unrelated
1265 | summary: change, unrelated
1252 |
1266 |
1253 o changeset: 0:e87515fd044a
1267 o changeset: 0:e87515fd044a
1254 user: test
1268 user: test
1255 date: Thu Jan 01 00:00:00 1970 +0000
1269 date: Thu Jan 01 00:00:00 1970 +0000
1256 summary: init, unrelated
1270 summary: init, unrelated
1257
1271
1258
1272
1259 $ hg --traceback log -f foo
1273 $ hg --traceback log -f foo
1260 changeset: 10:4dae8563d2c5
1274 changeset: 10:4dae8563d2c5
1261 tag: tip
1275 tag: tip
1262 parent: 9:7b35701b003e
1276 parent: 9:7b35701b003e
1263 parent: 4:88176d361b69
1277 parent: 4:88176d361b69
1264 user: test
1278 user: test
1265 date: Thu Jan 01 00:00:00 1970 +0000
1279 date: Thu Jan 01 00:00:00 1970 +0000
1266 summary: Last merge, related
1280 summary: Last merge, related
1267
1281
1268 changeset: 9:7b35701b003e
1282 changeset: 9:7b35701b003e
1269 parent: 8:e5416ad8a855
1283 parent: 8:e5416ad8a855
1270 parent: 7:87fe3144dcfa
1284 parent: 7:87fe3144dcfa
1271 user: test
1285 user: test
1272 date: Thu Jan 01 00:00:00 1970 +0000
1286 date: Thu Jan 01 00:00:00 1970 +0000
1273 summary: First merge, related
1287 summary: First merge, related
1274
1288
1275 changeset: 8:e5416ad8a855
1289 changeset: 8:e5416ad8a855
1276 parent: 6:dc6c325fe5ee
1290 parent: 6:dc6c325fe5ee
1277 user: test
1291 user: test
1278 date: Thu Jan 01 00:00:00 1970 +0000
1292 date: Thu Jan 01 00:00:00 1970 +0000
1279 summary: change foo in branch, related
1293 summary: change foo in branch, related
1280
1294
1281 changeset: 7:87fe3144dcfa
1295 changeset: 7:87fe3144dcfa
1282 user: test
1296 user: test
1283 date: Thu Jan 01 00:00:00 1970 +0000
1297 date: Thu Jan 01 00:00:00 1970 +0000
1284 summary: change foo, related
1298 summary: change foo, related
1285
1299
1286 changeset: 6:dc6c325fe5ee
1300 changeset: 6:dc6c325fe5ee
1287 user: test
1301 user: test
1288 date: Thu Jan 01 00:00:00 1970 +0000
1302 date: Thu Jan 01 00:00:00 1970 +0000
1289 summary: create foo, related
1303 summary: create foo, related
1290
1304
1291 changeset: 4:88176d361b69
1305 changeset: 4:88176d361b69
1292 user: test
1306 user: test
1293 date: Thu Jan 01 00:00:00 1970 +0000
1307 date: Thu Jan 01 00:00:00 1970 +0000
1294 summary: add foo, related
1308 summary: add foo, related
1295
1309
1296
1310
1297 Also check when maxrev < lastrevfilelog
1311 Also check when maxrev < lastrevfilelog
1298
1312
1299 $ hg --traceback log -f -r4 foo
1313 $ hg --traceback log -f -r4 foo
1300 changeset: 4:88176d361b69
1314 changeset: 4:88176d361b69
1301 user: test
1315 user: test
1302 date: Thu Jan 01 00:00:00 1970 +0000
1316 date: Thu Jan 01 00:00:00 1970 +0000
1303 summary: add foo, related
1317 summary: add foo, related
1304
1318
1305 $ cd ..
1319 $ cd ..
1306
1320
1307 Issue2383: hg log showing _less_ differences than hg diff
1321 Issue2383: hg log showing _less_ differences than hg diff
1308
1322
1309 $ hg init issue2383
1323 $ hg init issue2383
1310 $ cd issue2383
1324 $ cd issue2383
1311
1325
1312 Create a test repo:
1326 Create a test repo:
1313
1327
1314 $ echo a > a
1328 $ echo a > a
1315 $ hg ci -Am0
1329 $ hg ci -Am0
1316 adding a
1330 adding a
1317 $ echo b > b
1331 $ echo b > b
1318 $ hg ci -Am1
1332 $ hg ci -Am1
1319 adding b
1333 adding b
1320 $ hg co 0
1334 $ hg co 0
1321 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1335 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1322 $ echo b > a
1336 $ echo b > a
1323 $ hg ci -m2
1337 $ hg ci -m2
1324 created new head
1338 created new head
1325
1339
1326 Merge:
1340 Merge:
1327
1341
1328 $ hg merge
1342 $ hg merge
1329 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1343 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1330 (branch merge, don't forget to commit)
1344 (branch merge, don't forget to commit)
1331
1345
1332 Make sure there's a file listed in the merge to trigger the bug:
1346 Make sure there's a file listed in the merge to trigger the bug:
1333
1347
1334 $ echo c > a
1348 $ echo c > a
1335 $ hg ci -m3
1349 $ hg ci -m3
1336
1350
1337 Two files shown here in diff:
1351 Two files shown here in diff:
1338
1352
1339 $ hg diff --rev 2:3
1353 $ hg diff --rev 2:3
1340 diff -r b09be438c43a -r 8e07aafe1edc a
1354 diff -r b09be438c43a -r 8e07aafe1edc a
1341 --- a/a Thu Jan 01 00:00:00 1970 +0000
1355 --- a/a Thu Jan 01 00:00:00 1970 +0000
1342 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1356 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1343 @@ -1,1 +1,1 @@
1357 @@ -1,1 +1,1 @@
1344 -b
1358 -b
1345 +c
1359 +c
1346 diff -r b09be438c43a -r 8e07aafe1edc b
1360 diff -r b09be438c43a -r 8e07aafe1edc b
1347 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1361 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1348 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1362 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1349 @@ -0,0 +1,1 @@
1363 @@ -0,0 +1,1 @@
1350 +b
1364 +b
1351
1365
1352 Diff here should be the same:
1366 Diff here should be the same:
1353
1367
1354 $ hg log -vpr 3
1368 $ hg log -vpr 3
1355 changeset: 3:8e07aafe1edc
1369 changeset: 3:8e07aafe1edc
1356 tag: tip
1370 tag: tip
1357 parent: 2:b09be438c43a
1371 parent: 2:b09be438c43a
1358 parent: 1:925d80f479bb
1372 parent: 1:925d80f479bb
1359 user: test
1373 user: test
1360 date: Thu Jan 01 00:00:00 1970 +0000
1374 date: Thu Jan 01 00:00:00 1970 +0000
1361 files: a
1375 files: a
1362 description:
1376 description:
1363 3
1377 3
1364
1378
1365
1379
1366 diff -r b09be438c43a -r 8e07aafe1edc a
1380 diff -r b09be438c43a -r 8e07aafe1edc a
1367 --- a/a Thu Jan 01 00:00:00 1970 +0000
1381 --- a/a Thu Jan 01 00:00:00 1970 +0000
1368 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1382 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1369 @@ -1,1 +1,1 @@
1383 @@ -1,1 +1,1 @@
1370 -b
1384 -b
1371 +c
1385 +c
1372 diff -r b09be438c43a -r 8e07aafe1edc b
1386 diff -r b09be438c43a -r 8e07aafe1edc b
1373 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1387 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1374 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1388 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1375 @@ -0,0 +1,1 @@
1389 @@ -0,0 +1,1 @@
1376 +b
1390 +b
1377
1391
1378 $ cd ..
1392 $ cd ..
1379
1393
1380 'hg log -r rev fn' when last(filelog(fn)) != rev
1394 'hg log -r rev fn' when last(filelog(fn)) != rev
1381
1395
1382 $ hg init simplelog
1396 $ hg init simplelog
1383 $ cd simplelog
1397 $ cd simplelog
1384 $ echo f > a
1398 $ echo f > a
1385 $ hg ci -Am'a' -d '0 0'
1399 $ hg ci -Am'a' -d '0 0'
1386 adding a
1400 adding a
1387 $ echo f >> a
1401 $ echo f >> a
1388 $ hg ci -Am'a bis' -d '1 0'
1402 $ hg ci -Am'a bis' -d '1 0'
1389
1403
1390 $ hg log -r0 a
1404 $ hg log -r0 a
1391 changeset: 0:9f758d63dcde
1405 changeset: 0:9f758d63dcde
1392 user: test
1406 user: test
1393 date: Thu Jan 01 00:00:00 1970 +0000
1407 date: Thu Jan 01 00:00:00 1970 +0000
1394 summary: a
1408 summary: a
1395
1409
1396 enable obsolete to test hidden feature
1410 enable obsolete to test hidden feature
1397
1411
1398 $ cat >> $HGRCPATH << EOF
1412 $ cat >> $HGRCPATH << EOF
1399 > [experimental]
1413 > [experimental]
1400 > evolution=createmarkers
1414 > evolution=createmarkers
1401 > EOF
1415 > EOF
1402
1416
1403 $ hg log --template='{rev}:{node}\n'
1417 $ hg log --template='{rev}:{node}\n'
1404 1:a765632148dc55d38c35c4f247c618701886cb2f
1418 1:a765632148dc55d38c35c4f247c618701886cb2f
1405 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1419 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1406 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1420 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1407 $ hg up null -q
1421 $ hg up null -q
1408 $ hg log --template='{rev}:{node}\n'
1422 $ hg log --template='{rev}:{node}\n'
1409 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1423 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1410 $ hg log --template='{rev}:{node}\n' --hidden
1424 $ hg log --template='{rev}:{node}\n' --hidden
1411 1:a765632148dc55d38c35c4f247c618701886cb2f
1425 1:a765632148dc55d38c35c4f247c618701886cb2f
1412 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1426 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1413 $ hg log -r a
1427 $ hg log -r a
1414 abort: hidden revision 'a'!
1428 abort: hidden revision 'a'!
1415 (use --hidden to access hidden revisions)
1429 (use --hidden to access hidden revisions)
1416 [255]
1430 [255]
1417
1431
1418 test that parent prevent a changeset to be hidden
1432 test that parent prevent a changeset to be hidden
1419
1433
1420 $ hg up 1 -q --hidden
1434 $ hg up 1 -q --hidden
1421 $ hg log --template='{rev}:{node}\n'
1435 $ hg log --template='{rev}:{node}\n'
1422 1:a765632148dc55d38c35c4f247c618701886cb2f
1436 1:a765632148dc55d38c35c4f247c618701886cb2f
1423 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1437 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1424
1438
1425 test that second parent prevent a changeset to be hidden too
1439 test that second parent prevent a changeset to be hidden too
1426
1440
1427 $ hg debugsetparents 0 1 # nothing suitable to merge here
1441 $ hg debugsetparents 0 1 # nothing suitable to merge here
1428 $ hg log --template='{rev}:{node}\n'
1442 $ hg log --template='{rev}:{node}\n'
1429 1:a765632148dc55d38c35c4f247c618701886cb2f
1443 1:a765632148dc55d38c35c4f247c618701886cb2f
1430 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1444 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1431 $ hg debugsetparents 1
1445 $ hg debugsetparents 1
1432 $ hg up -q null
1446 $ hg up -q null
1433
1447
1434 bookmarks prevent a changeset being hidden
1448 bookmarks prevent a changeset being hidden
1435
1449
1436 $ hg bookmark --hidden -r 1 X
1450 $ hg bookmark --hidden -r 1 X
1437 $ hg log --template '{rev}:{node}\n'
1451 $ hg log --template '{rev}:{node}\n'
1438 1:a765632148dc55d38c35c4f247c618701886cb2f
1452 1:a765632148dc55d38c35c4f247c618701886cb2f
1439 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1453 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1440 $ hg bookmark -d X
1454 $ hg bookmark -d X
1441
1455
1442 divergent bookmarks are not hidden
1456 divergent bookmarks are not hidden
1443
1457
1444 $ hg bookmark --hidden -r 1 X@foo
1458 $ hg bookmark --hidden -r 1 X@foo
1445 $ hg log --template '{rev}:{node}\n'
1459 $ hg log --template '{rev}:{node}\n'
1446 1:a765632148dc55d38c35c4f247c618701886cb2f
1460 1:a765632148dc55d38c35c4f247c618701886cb2f
1447 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1461 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1448
1462
1449 clear extensions configuration
1463 clear extensions configuration
1450 $ echo '[extensions]' >> $HGRCPATH
1464 $ echo '[extensions]' >> $HGRCPATH
1451 $ echo "obs=!" >> $HGRCPATH
1465 $ echo "obs=!" >> $HGRCPATH
1452 $ cd ..
1466 $ cd ..
1453
1467
1454 test -u/-k for problematic encoding
1468 test -u/-k for problematic encoding
1455 # unicode: cp932:
1469 # unicode: cp932:
1456 # u30A2 0x83 0x41(= 'A')
1470 # u30A2 0x83 0x41(= 'A')
1457 # u30C2 0x83 0x61(= 'a')
1471 # u30C2 0x83 0x61(= 'a')
1458
1472
1459 $ hg init problematicencoding
1473 $ hg init problematicencoding
1460 $ cd problematicencoding
1474 $ cd problematicencoding
1461
1475
1462 $ python > setup.sh <<EOF
1476 $ python > setup.sh <<EOF
1463 > print u'''
1477 > print u'''
1464 > echo a > text
1478 > echo a > text
1465 > hg add text
1479 > hg add text
1466 > hg --encoding utf-8 commit -u '\u30A2' -m none
1480 > hg --encoding utf-8 commit -u '\u30A2' -m none
1467 > echo b > text
1481 > echo b > text
1468 > hg --encoding utf-8 commit -u '\u30C2' -m none
1482 > hg --encoding utf-8 commit -u '\u30C2' -m none
1469 > echo c > text
1483 > echo c > text
1470 > hg --encoding utf-8 commit -u none -m '\u30A2'
1484 > hg --encoding utf-8 commit -u none -m '\u30A2'
1471 > echo d > text
1485 > echo d > text
1472 > hg --encoding utf-8 commit -u none -m '\u30C2'
1486 > hg --encoding utf-8 commit -u none -m '\u30C2'
1473 > '''.encode('utf-8')
1487 > '''.encode('utf-8')
1474 > EOF
1488 > EOF
1475 $ sh < setup.sh
1489 $ sh < setup.sh
1476
1490
1477 test in problematic encoding
1491 test in problematic encoding
1478 $ python > test.sh <<EOF
1492 $ python > test.sh <<EOF
1479 > print u'''
1493 > print u'''
1480 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1494 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1481 > echo ====
1495 > echo ====
1482 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1496 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1483 > echo ====
1497 > echo ====
1484 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1498 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1485 > echo ====
1499 > echo ====
1486 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1500 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1487 > '''.encode('cp932')
1501 > '''.encode('cp932')
1488 > EOF
1502 > EOF
1489 $ sh < test.sh
1503 $ sh < test.sh
1490 0
1504 0
1491 ====
1505 ====
1492 1
1506 1
1493 ====
1507 ====
1494 2
1508 2
1495 0
1509 0
1496 ====
1510 ====
1497 3
1511 3
1498 1
1512 1
1499
1513
1500 $ cd ..
1514 $ cd ..
1501
1515
1502 test hg log on non-existent files and on directories
1516 test hg log on non-existent files and on directories
1503 $ hg init issue1340
1517 $ hg init issue1340
1504 $ cd issue1340
1518 $ cd issue1340
1505 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1519 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1506 $ echo 1 > d1/f1
1520 $ echo 1 > d1/f1
1507 $ echo 1 > D2/f1
1521 $ echo 1 > D2/f1
1508 $ echo 1 > D3.i/f1
1522 $ echo 1 > D3.i/f1
1509 $ echo 1 > d4.hg/f1
1523 $ echo 1 > d4.hg/f1
1510 $ echo 1 > d5.d/f1
1524 $ echo 1 > d5.d/f1
1511 $ echo 1 > .d6/f1
1525 $ echo 1 > .d6/f1
1512 $ hg -q add .
1526 $ hg -q add .
1513 $ hg commit -m "a bunch of weird directories"
1527 $ hg commit -m "a bunch of weird directories"
1514 $ hg log -l1 d1/f1 | grep changeset
1528 $ hg log -l1 d1/f1 | grep changeset
1515 changeset: 0:65624cd9070a
1529 changeset: 0:65624cd9070a
1516 $ hg log -l1 f1
1530 $ hg log -l1 f1
1517 $ hg log -l1 . | grep changeset
1531 $ hg log -l1 . | grep changeset
1518 changeset: 0:65624cd9070a
1532 changeset: 0:65624cd9070a
1519 $ hg log -l1 ./ | grep changeset
1533 $ hg log -l1 ./ | grep changeset
1520 changeset: 0:65624cd9070a
1534 changeset: 0:65624cd9070a
1521 $ hg log -l1 d1 | grep changeset
1535 $ hg log -l1 d1 | grep changeset
1522 changeset: 0:65624cd9070a
1536 changeset: 0:65624cd9070a
1523 $ hg log -l1 D2 | grep changeset
1537 $ hg log -l1 D2 | grep changeset
1524 changeset: 0:65624cd9070a
1538 changeset: 0:65624cd9070a
1525 $ hg log -l1 D2/f1 | grep changeset
1539 $ hg log -l1 D2/f1 | grep changeset
1526 changeset: 0:65624cd9070a
1540 changeset: 0:65624cd9070a
1527 $ hg log -l1 D3.i | grep changeset
1541 $ hg log -l1 D3.i | grep changeset
1528 changeset: 0:65624cd9070a
1542 changeset: 0:65624cd9070a
1529 $ hg log -l1 D3.i/f1 | grep changeset
1543 $ hg log -l1 D3.i/f1 | grep changeset
1530 changeset: 0:65624cd9070a
1544 changeset: 0:65624cd9070a
1531 $ hg log -l1 d4.hg | grep changeset
1545 $ hg log -l1 d4.hg | grep changeset
1532 changeset: 0:65624cd9070a
1546 changeset: 0:65624cd9070a
1533 $ hg log -l1 d4.hg/f1 | grep changeset
1547 $ hg log -l1 d4.hg/f1 | grep changeset
1534 changeset: 0:65624cd9070a
1548 changeset: 0:65624cd9070a
1535 $ hg log -l1 d5.d | grep changeset
1549 $ hg log -l1 d5.d | grep changeset
1536 changeset: 0:65624cd9070a
1550 changeset: 0:65624cd9070a
1537 $ hg log -l1 d5.d/f1 | grep changeset
1551 $ hg log -l1 d5.d/f1 | grep changeset
1538 changeset: 0:65624cd9070a
1552 changeset: 0:65624cd9070a
1539 $ hg log -l1 .d6 | grep changeset
1553 $ hg log -l1 .d6 | grep changeset
1540 changeset: 0:65624cd9070a
1554 changeset: 0:65624cd9070a
1541 $ hg log -l1 .d6/f1 | grep changeset
1555 $ hg log -l1 .d6/f1 | grep changeset
1542 changeset: 0:65624cd9070a
1556 changeset: 0:65624cd9070a
1543
1557
1544 issue3772: hg log -r :null showing revision 0 as well
1558 issue3772: hg log -r :null showing revision 0 as well
1545
1559
1546 $ hg log -r :null
1560 $ hg log -r :null
1547 changeset: 0:65624cd9070a
1561 changeset: 0:65624cd9070a
1548 tag: tip
1562 tag: tip
1549 user: test
1563 user: test
1550 date: Thu Jan 01 00:00:00 1970 +0000
1564 date: Thu Jan 01 00:00:00 1970 +0000
1551 summary: a bunch of weird directories
1565 summary: a bunch of weird directories
1552
1566
1553 changeset: -1:000000000000
1567 changeset: -1:000000000000
1554 user:
1568 user:
1555 date: Thu Jan 01 00:00:00 1970 +0000
1569 date: Thu Jan 01 00:00:00 1970 +0000
1556
1570
1557 $ hg log -r null:null
1571 $ hg log -r null:null
1558 changeset: -1:000000000000
1572 changeset: -1:000000000000
1559 user:
1573 user:
1560 date: Thu Jan 01 00:00:00 1970 +0000
1574 date: Thu Jan 01 00:00:00 1970 +0000
1561
1575
1562 Check that adding an arbitrary name shows up in log automatically
1576 Check that adding an arbitrary name shows up in log automatically
1563
1577
1564 $ cat > ../names.py <<EOF
1578 $ cat > ../names.py <<EOF
1565 > """A small extension to test adding arbitrary names to a repo"""
1579 > """A small extension to test adding arbitrary names to a repo"""
1566 > from mercurial.namespaces import namespace
1580 > from mercurial.namespaces import namespace
1567 >
1581 >
1568 > def reposetup(ui, repo):
1582 > def reposetup(ui, repo):
1569 > foo = {'foo': repo[0].node()}
1583 > foo = {'foo': repo[0].node()}
1570 > names = lambda r: foo.keys()
1584 > names = lambda r: foo.keys()
1571 > namemap = lambda r, name: foo.get(name)
1585 > namemap = lambda r, name: foo.get(name)
1572 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
1586 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
1573 > if n == node]
1587 > if n == node]
1574 > ns = namespace("bars", templatename="bar", logname="barlog",
1588 > ns = namespace("bars", templatename="bar", logname="barlog",
1575 > colorname="barcolor", listnames=names, namemap=namemap,
1589 > colorname="barcolor", listnames=names, namemap=namemap,
1576 > nodemap=nodemap)
1590 > nodemap=nodemap)
1577 >
1591 >
1578 > repo.names.addnamespace(ns)
1592 > repo.names.addnamespace(ns)
1579 > EOF
1593 > EOF
1580
1594
1581 $ hg --config extensions.names=../names.py log -r 0
1595 $ hg --config extensions.names=../names.py log -r 0
1582 changeset: 0:65624cd9070a
1596 changeset: 0:65624cd9070a
1583 tag: tip
1597 tag: tip
1584 barlog: foo
1598 barlog: foo
1585 user: test
1599 user: test
1586 date: Thu Jan 01 00:00:00 1970 +0000
1600 date: Thu Jan 01 00:00:00 1970 +0000
1587 summary: a bunch of weird directories
1601 summary: a bunch of weird directories
1588
1602
1589 $ hg --config extensions.names=../names.py \
1603 $ hg --config extensions.names=../names.py \
1590 > --config extensions.color= --config color.log.barcolor=red \
1604 > --config extensions.color= --config color.log.barcolor=red \
1591 > --color=always log -r 0
1605 > --color=always log -r 0
1592 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
1606 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
1593 tag: tip
1607 tag: tip
1594 \x1b[0;31mbarlog: foo\x1b[0m (esc)
1608 \x1b[0;31mbarlog: foo\x1b[0m (esc)
1595 user: test
1609 user: test
1596 date: Thu Jan 01 00:00:00 1970 +0000
1610 date: Thu Jan 01 00:00:00 1970 +0000
1597 summary: a bunch of weird directories
1611 summary: a bunch of weird directories
1598
1612
1599 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
1613 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
1600 foo
1614 foo
1601
1615
1602 $ cd ..
1616 $ cd ..
1603
1617
1604 hg log -f dir across branches
1618 hg log -f dir across branches
1605
1619
1606 $ hg init acrossbranches
1620 $ hg init acrossbranches
1607 $ cd acrossbranches
1621 $ cd acrossbranches
1608 $ mkdir d
1622 $ mkdir d
1609 $ echo a > d/a && hg ci -Aqm a
1623 $ echo a > d/a && hg ci -Aqm a
1610 $ echo b > d/a && hg ci -Aqm b
1624 $ echo b > d/a && hg ci -Aqm b
1611 $ hg up -q 0
1625 $ hg up -q 0
1612 $ echo b > d/a && hg ci -Aqm c
1626 $ echo b > d/a && hg ci -Aqm c
1613 $ hg log -f d -T '{desc}' -G
1627 $ hg log -f d -T '{desc}' -G
1614 @ c
1628 @ c
1615 |
1629 |
1616 o a
1630 o a
1617
1631
1618 $ hg log -f d/a -T '{desc}' -G
1632 $ hg log -f d/a -T '{desc}' -G
1619 @ c
1633 @ c
1620 |
1634 |
1621 o a
1635 o a
1622
1636
1623 $ cd ..
1637 $ cd ..
1624
1638
1625 hg log -f with linkrev pointing to another branch
1639 hg log -f with linkrev pointing to another branch
1626 -------------------------------------------------
1640 -------------------------------------------------
1627
1641
1628 create history with a filerev whose linkrev points to another branch
1642 create history with a filerev whose linkrev points to another branch
1629
1643
1630 $ hg init branchedlinkrev
1644 $ hg init branchedlinkrev
1631 $ cd branchedlinkrev
1645 $ cd branchedlinkrev
1632 $ echo 1 > a
1646 $ echo 1 > a
1633 $ hg commit -Am 'content1'
1647 $ hg commit -Am 'content1'
1634 adding a
1648 adding a
1635 $ echo 2 > a
1649 $ echo 2 > a
1636 $ hg commit -m 'content2'
1650 $ hg commit -m 'content2'
1637 $ hg up --rev 'desc(content1)'
1651 $ hg up --rev 'desc(content1)'
1638 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1652 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1639 $ echo unrelated > unrelated
1653 $ echo unrelated > unrelated
1640 $ hg commit -Am 'unrelated'
1654 $ hg commit -Am 'unrelated'
1641 adding unrelated
1655 adding unrelated
1642 created new head
1656 created new head
1643 $ hg graft -r 'desc(content2)'
1657 $ hg graft -r 'desc(content2)'
1644 grafting 1:2294ae80ad84 "content2"
1658 grafting 1:2294ae80ad84 "content2"
1645 $ echo 3 > a
1659 $ echo 3 > a
1646 $ hg commit -m 'content3'
1660 $ hg commit -m 'content3'
1647 $ hg log -G
1661 $ hg log -G
1648 @ changeset: 4:50b9b36e9c5d
1662 @ changeset: 4:50b9b36e9c5d
1649 | tag: tip
1663 | tag: tip
1650 | user: test
1664 | user: test
1651 | date: Thu Jan 01 00:00:00 1970 +0000
1665 | date: Thu Jan 01 00:00:00 1970 +0000
1652 | summary: content3
1666 | summary: content3
1653 |
1667 |
1654 o changeset: 3:15b2327059e5
1668 o changeset: 3:15b2327059e5
1655 | user: test
1669 | user: test
1656 | date: Thu Jan 01 00:00:00 1970 +0000
1670 | date: Thu Jan 01 00:00:00 1970 +0000
1657 | summary: content2
1671 | summary: content2
1658 |
1672 |
1659 o changeset: 2:2029acd1168c
1673 o changeset: 2:2029acd1168c
1660 | parent: 0:ae0a3c9f9e95
1674 | parent: 0:ae0a3c9f9e95
1661 | user: test
1675 | user: test
1662 | date: Thu Jan 01 00:00:00 1970 +0000
1676 | date: Thu Jan 01 00:00:00 1970 +0000
1663 | summary: unrelated
1677 | summary: unrelated
1664 |
1678 |
1665 | o changeset: 1:2294ae80ad84
1679 | o changeset: 1:2294ae80ad84
1666 |/ user: test
1680 |/ user: test
1667 | date: Thu Jan 01 00:00:00 1970 +0000
1681 | date: Thu Jan 01 00:00:00 1970 +0000
1668 | summary: content2
1682 | summary: content2
1669 |
1683 |
1670 o changeset: 0:ae0a3c9f9e95
1684 o changeset: 0:ae0a3c9f9e95
1671 user: test
1685 user: test
1672 date: Thu Jan 01 00:00:00 1970 +0000
1686 date: Thu Jan 01 00:00:00 1970 +0000
1673 summary: content1
1687 summary: content1
1674
1688
1675
1689
1676 log -f on the file should list the graft result.
1690 log -f on the file should list the graft result.
1677
1691
1678 $ hg log -Gf a
1692 $ hg log -Gf a
1679 @ changeset: 4:50b9b36e9c5d
1693 @ changeset: 4:50b9b36e9c5d
1680 | tag: tip
1694 | tag: tip
1681 | user: test
1695 | user: test
1682 | date: Thu Jan 01 00:00:00 1970 +0000
1696 | date: Thu Jan 01 00:00:00 1970 +0000
1683 | summary: content3
1697 | summary: content3
1684 |
1698 |
1685 o changeset: 3:15b2327059e5
1699 o changeset: 3:15b2327059e5
1686 | user: test
1700 | user: test
1687 | date: Thu Jan 01 00:00:00 1970 +0000
1701 | date: Thu Jan 01 00:00:00 1970 +0000
1688 | summary: content2
1702 | summary: content2
1689 |
1703 |
1690 o changeset: 0:ae0a3c9f9e95
1704 o changeset: 0:ae0a3c9f9e95
1691 user: test
1705 user: test
1692 date: Thu Jan 01 00:00:00 1970 +0000
1706 date: Thu Jan 01 00:00:00 1970 +0000
1693 summary: content1
1707 summary: content1
1694
1708
1695
1709
1696 plain log lists the original version
1710 plain log lists the original version
1697 (XXX we should probably list both)
1711 (XXX we should probably list both)
1698
1712
1699 $ hg log -G a
1713 $ hg log -G a
1700 @ changeset: 4:50b9b36e9c5d
1714 @ changeset: 4:50b9b36e9c5d
1701 | tag: tip
1715 | tag: tip
1702 | user: test
1716 | user: test
1703 | date: Thu Jan 01 00:00:00 1970 +0000
1717 | date: Thu Jan 01 00:00:00 1970 +0000
1704 | summary: content3
1718 | summary: content3
1705 |
1719 |
1706 | o changeset: 1:2294ae80ad84
1720 | o changeset: 1:2294ae80ad84
1707 |/ user: test
1721 |/ user: test
1708 | date: Thu Jan 01 00:00:00 1970 +0000
1722 | date: Thu Jan 01 00:00:00 1970 +0000
1709 | summary: content2
1723 | summary: content2
1710 |
1724 |
1711 o changeset: 0:ae0a3c9f9e95
1725 o changeset: 0:ae0a3c9f9e95
1712 user: test
1726 user: test
1713 date: Thu Jan 01 00:00:00 1970 +0000
1727 date: Thu Jan 01 00:00:00 1970 +0000
1714 summary: content1
1728 summary: content1
1715
1729
1716
1730
1717 hg log -f from the grafted changeset
1731 hg log -f from the grafted changeset
1718 (The bootstrap should properly take the topology in account)
1732 (The bootstrap should properly take the topology in account)
1719
1733
1720 $ hg up 'desc(content3)^'
1734 $ hg up 'desc(content3)^'
1721 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1735 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1722 $ hg log -Gf a
1736 $ hg log -Gf a
1723 @ changeset: 3:15b2327059e5
1737 @ changeset: 3:15b2327059e5
1724 | user: test
1738 | user: test
1725 | date: Thu Jan 01 00:00:00 1970 +0000
1739 | date: Thu Jan 01 00:00:00 1970 +0000
1726 | summary: content2
1740 | summary: content2
1727 |
1741 |
1728 o changeset: 0:ae0a3c9f9e95
1742 o changeset: 0:ae0a3c9f9e95
1729 user: test
1743 user: test
1730 date: Thu Jan 01 00:00:00 1970 +0000
1744 date: Thu Jan 01 00:00:00 1970 +0000
1731 summary: content1
1745 summary: content1
1732
1746
1733
1747
1734 Test that we use the first non-hidden changeset in that case.
1748 Test that we use the first non-hidden changeset in that case.
1735
1749
1736 (hide the changeset)
1750 (hide the changeset)
1737
1751
1738 $ hg log -T '{node}\n' -r 1
1752 $ hg log -T '{node}\n' -r 1
1739 2294ae80ad8447bc78383182eeac50cb049df623
1753 2294ae80ad8447bc78383182eeac50cb049df623
1740 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
1754 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
1741 $ hg log -G
1755 $ hg log -G
1742 o changeset: 4:50b9b36e9c5d
1756 o changeset: 4:50b9b36e9c5d
1743 | tag: tip
1757 | tag: tip
1744 | user: test
1758 | user: test
1745 | date: Thu Jan 01 00:00:00 1970 +0000
1759 | date: Thu Jan 01 00:00:00 1970 +0000
1746 | summary: content3
1760 | summary: content3
1747 |
1761 |
1748 @ changeset: 3:15b2327059e5
1762 @ changeset: 3:15b2327059e5
1749 | user: test
1763 | user: test
1750 | date: Thu Jan 01 00:00:00 1970 +0000
1764 | date: Thu Jan 01 00:00:00 1970 +0000
1751 | summary: content2
1765 | summary: content2
1752 |
1766 |
1753 o changeset: 2:2029acd1168c
1767 o changeset: 2:2029acd1168c
1754 | parent: 0:ae0a3c9f9e95
1768 | parent: 0:ae0a3c9f9e95
1755 | user: test
1769 | user: test
1756 | date: Thu Jan 01 00:00:00 1970 +0000
1770 | date: Thu Jan 01 00:00:00 1970 +0000
1757 | summary: unrelated
1771 | summary: unrelated
1758 |
1772 |
1759 o changeset: 0:ae0a3c9f9e95
1773 o changeset: 0:ae0a3c9f9e95
1760 user: test
1774 user: test
1761 date: Thu Jan 01 00:00:00 1970 +0000
1775 date: Thu Jan 01 00:00:00 1970 +0000
1762 summary: content1
1776 summary: content1
1763
1777
1764
1778
1765 Check that log on the file does not drop the file revision.
1779 Check that log on the file does not drop the file revision.
1766
1780
1767 $ hg log -G a
1781 $ hg log -G a
1768 o changeset: 4:50b9b36e9c5d
1782 o changeset: 4:50b9b36e9c5d
1769 | tag: tip
1783 | tag: tip
1770 | user: test
1784 | user: test
1771 | date: Thu Jan 01 00:00:00 1970 +0000
1785 | date: Thu Jan 01 00:00:00 1970 +0000
1772 | summary: content3
1786 | summary: content3
1773 |
1787 |
1774 @ changeset: 3:15b2327059e5
1788 @ changeset: 3:15b2327059e5
1775 | user: test
1789 | user: test
1776 | date: Thu Jan 01 00:00:00 1970 +0000
1790 | date: Thu Jan 01 00:00:00 1970 +0000
1777 | summary: content2
1791 | summary: content2
1778 |
1792 |
1779 o changeset: 0:ae0a3c9f9e95
1793 o changeset: 0:ae0a3c9f9e95
1780 user: test
1794 user: test
1781 date: Thu Jan 01 00:00:00 1970 +0000
1795 date: Thu Jan 01 00:00:00 1970 +0000
1782 summary: content1
1796 summary: content1
1783
1797
1784
1798
1785 Even when a head revision is linkrev-shadowed.
1799 Even when a head revision is linkrev-shadowed.
1786
1800
1787 $ hg log -T '{node}\n' -r 4
1801 $ hg log -T '{node}\n' -r 4
1788 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1802 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1789 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1803 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1790 $ hg log -G a
1804 $ hg log -G a
1791 @ changeset: 3:15b2327059e5
1805 @ changeset: 3:15b2327059e5
1792 | tag: tip
1806 | tag: tip
1793 | user: test
1807 | user: test
1794 | date: Thu Jan 01 00:00:00 1970 +0000
1808 | date: Thu Jan 01 00:00:00 1970 +0000
1795 | summary: content2
1809 | summary: content2
1796 |
1810 |
1797 o changeset: 0:ae0a3c9f9e95
1811 o changeset: 0:ae0a3c9f9e95
1798 user: test
1812 user: test
1799 date: Thu Jan 01 00:00:00 1970 +0000
1813 date: Thu Jan 01 00:00:00 1970 +0000
1800 summary: content1
1814 summary: content1
1801
1815
1802
1816
1803 $ cd ..
1817 $ cd ..
1804
1818
1805 Even when the file revision is missing from some head:
1819 Even when the file revision is missing from some head:
1806
1820
1807 $ hg init issue4490
1821 $ hg init issue4490
1808 $ cd issue4490
1822 $ cd issue4490
1809 $ echo '[experimental]' >> .hg/hgrc
1823 $ echo '[experimental]' >> .hg/hgrc
1810 $ echo 'evolution=createmarkers' >> .hg/hgrc
1824 $ echo 'evolution=createmarkers' >> .hg/hgrc
1811 $ echo a > a
1825 $ echo a > a
1812 $ hg ci -Am0
1826 $ hg ci -Am0
1813 adding a
1827 adding a
1814 $ echo b > b
1828 $ echo b > b
1815 $ hg ci -Am1
1829 $ hg ci -Am1
1816 adding b
1830 adding b
1817 $ echo B > b
1831 $ echo B > b
1818 $ hg ci --amend -m 1
1832 $ hg ci --amend -m 1
1819 $ hg up 0
1833 $ hg up 0
1820 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1834 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1821 $ echo c > c
1835 $ echo c > c
1822 $ hg ci -Am2
1836 $ hg ci -Am2
1823 adding c
1837 adding c
1824 created new head
1838 created new head
1825 $ hg up 'head() and not .'
1839 $ hg up 'head() and not .'
1826 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1840 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1827 $ hg log -G
1841 $ hg log -G
1828 o changeset: 4:db815d6d32e6
1842 o changeset: 4:db815d6d32e6
1829 | tag: tip
1843 | tag: tip
1830 | parent: 0:f7b1eb17ad24
1844 | parent: 0:f7b1eb17ad24
1831 | user: test
1845 | user: test
1832 | date: Thu Jan 01 00:00:00 1970 +0000
1846 | date: Thu Jan 01 00:00:00 1970 +0000
1833 | summary: 2
1847 | summary: 2
1834 |
1848 |
1835 | @ changeset: 3:9bc8ce7f9356
1849 | @ changeset: 3:9bc8ce7f9356
1836 |/ parent: 0:f7b1eb17ad24
1850 |/ parent: 0:f7b1eb17ad24
1837 | user: test
1851 | user: test
1838 | date: Thu Jan 01 00:00:00 1970 +0000
1852 | date: Thu Jan 01 00:00:00 1970 +0000
1839 | summary: 1
1853 | summary: 1
1840 |
1854 |
1841 o changeset: 0:f7b1eb17ad24
1855 o changeset: 0:f7b1eb17ad24
1842 user: test
1856 user: test
1843 date: Thu Jan 01 00:00:00 1970 +0000
1857 date: Thu Jan 01 00:00:00 1970 +0000
1844 summary: 0
1858 summary: 0
1845
1859
1846 $ hg log -f -G b
1860 $ hg log -f -G b
1847 @ changeset: 3:9bc8ce7f9356
1861 @ changeset: 3:9bc8ce7f9356
1848 | parent: 0:f7b1eb17ad24
1862 | parent: 0:f7b1eb17ad24
1849 | user: test
1863 | user: test
1850 | date: Thu Jan 01 00:00:00 1970 +0000
1864 | date: Thu Jan 01 00:00:00 1970 +0000
1851 | summary: 1
1865 | summary: 1
1852 |
1866 |
1853 $ hg log -G b
1867 $ hg log -G b
1854 @ changeset: 3:9bc8ce7f9356
1868 @ changeset: 3:9bc8ce7f9356
1855 | parent: 0:f7b1eb17ad24
1869 | parent: 0:f7b1eb17ad24
1856 | user: test
1870 | user: test
1857 | date: Thu Jan 01 00:00:00 1970 +0000
1871 | date: Thu Jan 01 00:00:00 1970 +0000
1858 | summary: 1
1872 | summary: 1
1859 |
1873 |
1860 $ cd ..
1874 $ cd ..
1861
1875
1862 Check proper report when the manifest changes but not the file issue4499
1876 Check proper report when the manifest changes but not the file issue4499
1863 ------------------------------------------------------------------------
1877 ------------------------------------------------------------------------
1864
1878
1865 $ hg init issue4499
1879 $ hg init issue4499
1866 $ cd issue4499
1880 $ cd issue4499
1867 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
1881 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
1868 > echo 1 > $f;
1882 > echo 1 > $f;
1869 > hg add $f;
1883 > hg add $f;
1870 > done
1884 > done
1871 $ hg commit -m 'A1B1C1'
1885 $ hg commit -m 'A1B1C1'
1872 $ echo 2 > A
1886 $ echo 2 > A
1873 $ echo 2 > B
1887 $ echo 2 > B
1874 $ echo 2 > C
1888 $ echo 2 > C
1875 $ hg commit -m 'A2B2C2'
1889 $ hg commit -m 'A2B2C2'
1876 $ hg up 0
1890 $ hg up 0
1877 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1891 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1878 $ echo 3 > A
1892 $ echo 3 > A
1879 $ echo 2 > B
1893 $ echo 2 > B
1880 $ echo 2 > C
1894 $ echo 2 > C
1881 $ hg commit -m 'A3B2C2'
1895 $ hg commit -m 'A3B2C2'
1882 created new head
1896 created new head
1883
1897
1884 $ hg log -G
1898 $ hg log -G
1885 @ changeset: 2:fe5fc3d0eb17
1899 @ changeset: 2:fe5fc3d0eb17
1886 | tag: tip
1900 | tag: tip
1887 | parent: 0:abf4f0e38563
1901 | parent: 0:abf4f0e38563
1888 | user: test
1902 | user: test
1889 | date: Thu Jan 01 00:00:00 1970 +0000
1903 | date: Thu Jan 01 00:00:00 1970 +0000
1890 | summary: A3B2C2
1904 | summary: A3B2C2
1891 |
1905 |
1892 | o changeset: 1:07dcc6b312c0
1906 | o changeset: 1:07dcc6b312c0
1893 |/ user: test
1907 |/ user: test
1894 | date: Thu Jan 01 00:00:00 1970 +0000
1908 | date: Thu Jan 01 00:00:00 1970 +0000
1895 | summary: A2B2C2
1909 | summary: A2B2C2
1896 |
1910 |
1897 o changeset: 0:abf4f0e38563
1911 o changeset: 0:abf4f0e38563
1898 user: test
1912 user: test
1899 date: Thu Jan 01 00:00:00 1970 +0000
1913 date: Thu Jan 01 00:00:00 1970 +0000
1900 summary: A1B1C1
1914 summary: A1B1C1
1901
1915
1902
1916
1903 Log -f on B should reports current changesets
1917 Log -f on B should reports current changesets
1904
1918
1905 $ hg log -fG B
1919 $ hg log -fG B
1906 @ changeset: 2:fe5fc3d0eb17
1920 @ changeset: 2:fe5fc3d0eb17
1907 | tag: tip
1921 | tag: tip
1908 | parent: 0:abf4f0e38563
1922 | parent: 0:abf4f0e38563
1909 | user: test
1923 | user: test
1910 | date: Thu Jan 01 00:00:00 1970 +0000
1924 | date: Thu Jan 01 00:00:00 1970 +0000
1911 | summary: A3B2C2
1925 | summary: A3B2C2
1912 |
1926 |
1913 o changeset: 0:abf4f0e38563
1927 o changeset: 0:abf4f0e38563
1914 user: test
1928 user: test
1915 date: Thu Jan 01 00:00:00 1970 +0000
1929 date: Thu Jan 01 00:00:00 1970 +0000
1916 summary: A1B1C1
1930 summary: A1B1C1
1917
1931
1918 $ cd ..
1932 $ cd ..
@@ -1,1267 +1,1271 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
90
91 $ hg clone --quiet -U -r 7 . ../remote1
91 $ hg clone --quiet -U -r 7 . ../remote1
92 $ hg clone --quiet -U -r 8 . ../remote2
92 $ hg clone --quiet -U -r 8 . ../remote2
93 $ echo "[paths]" >> .hg/hgrc
93 $ echo "[paths]" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
95
95
96 names that should work without quoting
96 names that should work without quoting
97
97
98 $ try a
98 $ try a
99 ('symbol', 'a')
99 ('symbol', 'a')
100 0
100 0
101 $ try b-a
101 $ try b-a
102 (minus
102 (minus
103 ('symbol', 'b')
103 ('symbol', 'b')
104 ('symbol', 'a'))
104 ('symbol', 'a'))
105 1
105 1
106 $ try _a_b_c_
106 $ try _a_b_c_
107 ('symbol', '_a_b_c_')
107 ('symbol', '_a_b_c_')
108 6
108 6
109 $ try _a_b_c_-a
109 $ try _a_b_c_-a
110 (minus
110 (minus
111 ('symbol', '_a_b_c_')
111 ('symbol', '_a_b_c_')
112 ('symbol', 'a'))
112 ('symbol', 'a'))
113 6
113 6
114 $ try .a.b.c.
114 $ try .a.b.c.
115 ('symbol', '.a.b.c.')
115 ('symbol', '.a.b.c.')
116 7
116 7
117 $ try .a.b.c.-a
117 $ try .a.b.c.-a
118 (minus
118 (minus
119 ('symbol', '.a.b.c.')
119 ('symbol', '.a.b.c.')
120 ('symbol', 'a'))
120 ('symbol', 'a'))
121 7
121 7
122 $ try -- '-a-b-c-' # complains
122 $ try -- '-a-b-c-' # complains
123 hg: parse error at 7: not a prefix: end
123 hg: parse error at 7: not a prefix: end
124 [255]
124 [255]
125 $ log -a-b-c- # succeeds with fallback
125 $ log -a-b-c- # succeeds with fallback
126 4
126 4
127
127
128 $ try -- -a-b-c--a # complains
128 $ try -- -a-b-c--a # complains
129 (minus
129 (minus
130 (minus
130 (minus
131 (minus
131 (minus
132 (negate
132 (negate
133 ('symbol', 'a'))
133 ('symbol', 'a'))
134 ('symbol', 'b'))
134 ('symbol', 'b'))
135 ('symbol', 'c'))
135 ('symbol', 'c'))
136 (negate
136 (negate
137 ('symbol', 'a')))
137 ('symbol', 'a')))
138 abort: unknown revision '-a'!
138 abort: unknown revision '-a'!
139 [255]
139 [255]
140 $ try Γ©
140 $ try Γ©
141 ('symbol', '\xc3\xa9')
141 ('symbol', '\xc3\xa9')
142 9
142 9
143
143
144 no quoting needed
144 no quoting needed
145
145
146 $ log ::a-b-c-
146 $ log ::a-b-c-
147 0
147 0
148 1
148 1
149 2
149 2
150
150
151 quoting needed
151 quoting needed
152
152
153 $ try '"-a-b-c-"-a'
153 $ try '"-a-b-c-"-a'
154 (minus
154 (minus
155 ('string', '-a-b-c-')
155 ('string', '-a-b-c-')
156 ('symbol', 'a'))
156 ('symbol', 'a'))
157 4
157 4
158
158
159 $ log '1 or 2'
159 $ log '1 or 2'
160 1
160 1
161 2
161 2
162 $ log '1|2'
162 $ log '1|2'
163 1
163 1
164 2
164 2
165 $ log '1 and 2'
165 $ log '1 and 2'
166 $ log '1&2'
166 $ log '1&2'
167 $ try '1&2|3' # precedence - and is higher
167 $ try '1&2|3' # precedence - and is higher
168 (or
168 (or
169 (and
169 (and
170 ('symbol', '1')
170 ('symbol', '1')
171 ('symbol', '2'))
171 ('symbol', '2'))
172 ('symbol', '3'))
172 ('symbol', '3'))
173 3
173 3
174 $ try '1|2&3'
174 $ try '1|2&3'
175 (or
175 (or
176 ('symbol', '1')
176 ('symbol', '1')
177 (and
177 (and
178 ('symbol', '2')
178 ('symbol', '2')
179 ('symbol', '3')))
179 ('symbol', '3')))
180 1
180 1
181 $ try '1&2&3' # associativity
181 $ try '1&2&3' # associativity
182 (and
182 (and
183 (and
183 (and
184 ('symbol', '1')
184 ('symbol', '1')
185 ('symbol', '2'))
185 ('symbol', '2'))
186 ('symbol', '3'))
186 ('symbol', '3'))
187 $ try '1|(2|3)'
187 $ try '1|(2|3)'
188 (or
188 (or
189 ('symbol', '1')
189 ('symbol', '1')
190 (group
190 (group
191 (or
191 (or
192 ('symbol', '2')
192 ('symbol', '2')
193 ('symbol', '3'))))
193 ('symbol', '3'))))
194 1
194 1
195 2
195 2
196 3
196 3
197 $ log '1.0' # tag
197 $ log '1.0' # tag
198 6
198 6
199 $ log 'a' # branch
199 $ log 'a' # branch
200 0
200 0
201 $ log '2785f51ee'
201 $ log '2785f51ee'
202 0
202 0
203 $ log 'date(2005)'
203 $ log 'date(2005)'
204 4
204 4
205 $ log 'date(this is a test)'
205 $ log 'date(this is a test)'
206 hg: parse error at 10: unexpected token: symbol
206 hg: parse error at 10: unexpected token: symbol
207 [255]
207 [255]
208 $ log 'date()'
208 $ log 'date()'
209 hg: parse error: date requires a string
209 hg: parse error: date requires a string
210 [255]
210 [255]
211 $ log 'date'
211 $ log 'date'
212 hg: parse error: can't use date here
212 hg: parse error: can't use date here
213 [255]
213 [255]
214 $ log 'date('
214 $ log 'date('
215 hg: parse error at 5: not a prefix: end
215 hg: parse error at 5: not a prefix: end
216 [255]
216 [255]
217 $ log 'date(tip)'
217 $ log 'date(tip)'
218 abort: invalid date: 'tip'
218 abort: invalid date: 'tip'
219 [255]
219 [255]
220 $ log '"date"'
220 $ log '"date"'
221 abort: unknown revision 'date'!
221 abort: unknown revision 'date'!
222 [255]
222 [255]
223 $ log 'date(2005) and 1::'
223 $ log 'date(2005) and 1::'
224 4
224 4
225
225
226 ancestor can accept 0 or more arguments
226 ancestor can accept 0 or more arguments
227
227
228 $ log 'ancestor()'
228 $ log 'ancestor()'
229 $ log 'ancestor(1)'
229 $ log 'ancestor(1)'
230 1
230 1
231 $ log 'ancestor(4,5)'
231 $ log 'ancestor(4,5)'
232 1
232 1
233 $ log 'ancestor(4,5) and 4'
233 $ log 'ancestor(4,5) and 4'
234 $ log 'ancestor(0,0,1,3)'
234 $ log 'ancestor(0,0,1,3)'
235 0
235 0
236 $ log 'ancestor(3,1,5,3,5,1)'
236 $ log 'ancestor(3,1,5,3,5,1)'
237 1
237 1
238 $ log 'ancestor(0,1,3,5)'
238 $ log 'ancestor(0,1,3,5)'
239 0
239 0
240 $ log 'ancestor(1,2,3,4,5)'
240 $ log 'ancestor(1,2,3,4,5)'
241 1
241 1
242 $ log 'ancestors(5)'
242 $ log 'ancestors(5)'
243 0
243 0
244 1
244 1
245 3
245 3
246 5
246 5
247 $ log 'ancestor(ancestors(5))'
247 $ log 'ancestor(ancestors(5))'
248 0
248 0
249 $ log 'author(bob)'
249 $ log 'author(bob)'
250 2
250 2
251 $ log 'author("re:bob|test")'
251 $ log 'author("re:bob|test")'
252 0
252 0
253 1
253 1
254 2
254 2
255 3
255 3
256 4
256 4
257 5
257 5
258 6
258 6
259 7
259 7
260 8
260 8
261 9
261 9
262 $ log 'branch(Γ©)'
262 $ log 'branch(Γ©)'
263 8
263 8
264 9
264 9
265 $ log 'branch(a)'
265 $ log 'branch(a)'
266 0
266 0
267 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
267 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
268 0 a
268 0 a
269 2 a-b-c-
269 2 a-b-c-
270 3 +a+b+c+
270 3 +a+b+c+
271 4 -a-b-c-
271 4 -a-b-c-
272 5 !a/b/c/
272 5 !a/b/c/
273 6 _a_b_c_
273 6 _a_b_c_
274 7 .a.b.c.
274 7 .a.b.c.
275 $ log 'children(ancestor(4,5))'
275 $ log 'children(ancestor(4,5))'
276 2
276 2
277 3
277 3
278 $ log 'closed()'
278 $ log 'closed()'
279 $ log 'contains(a)'
279 $ log 'contains(a)'
280 0
280 0
281 1
281 1
282 3
282 3
283 5
283 5
284 $ log 'contains("../repo/a")'
284 $ log 'contains("../repo/a")'
285 0
285 0
286 1
286 1
287 3
287 3
288 5
288 5
289 $ log 'desc(B)'
289 $ log 'desc(B)'
290 5
290 5
291 $ log 'descendants(2 or 3)'
291 $ log 'descendants(2 or 3)'
292 2
292 2
293 3
293 3
294 4
294 4
295 5
295 5
296 6
296 6
297 7
297 7
298 8
298 8
299 9
299 9
300 $ log 'file("b*")'
300 $ log 'file("b*")'
301 1
301 1
302 4
302 4
303 $ log 'filelog("b")'
303 $ log 'filelog("b")'
304 1
304 1
305 4
305 4
306 $ log 'filelog("../repo/b")'
306 $ log 'filelog("../repo/b")'
307 1
307 1
308 4
308 4
309 $ log 'follow()'
309 $ log 'follow()'
310 0
310 0
311 1
311 1
312 2
312 2
313 4
313 4
314 8
314 8
315 9
315 9
316 $ log 'grep("issue\d+")'
316 $ log 'grep("issue\d+")'
317 6
317 6
318 $ try 'grep("(")' # invalid regular expression
318 $ try 'grep("(")' # invalid regular expression
319 (func
319 (func
320 ('symbol', 'grep')
320 ('symbol', 'grep')
321 ('string', '('))
321 ('string', '('))
322 hg: parse error: invalid match pattern: unbalanced parenthesis
322 hg: parse error: invalid match pattern: unbalanced parenthesis
323 [255]
323 [255]
324 $ try 'grep("\bissue\d+")'
324 $ try 'grep("\bissue\d+")'
325 (func
325 (func
326 ('symbol', 'grep')
326 ('symbol', 'grep')
327 ('string', '\x08issue\\d+'))
327 ('string', '\x08issue\\d+'))
328 $ try 'grep(r"\bissue\d+")'
328 $ try 'grep(r"\bissue\d+")'
329 (func
329 (func
330 ('symbol', 'grep')
330 ('symbol', 'grep')
331 ('string', '\\bissue\\d+'))
331 ('string', '\\bissue\\d+'))
332 6
332 6
333 $ try 'grep(r"\")'
333 $ try 'grep(r"\")'
334 hg: parse error at 7: unterminated string
334 hg: parse error at 7: unterminated string
335 [255]
335 [255]
336 $ log 'head()'
336 $ log 'head()'
337 0
337 0
338 1
338 1
339 2
339 2
340 3
340 3
341 4
341 4
342 5
342 5
343 6
343 6
344 7
344 7
345 9
345 9
346 $ log 'heads(6::)'
346 $ log 'heads(6::)'
347 7
347 7
348 $ log 'keyword(issue)'
348 $ log 'keyword(issue)'
349 6
349 6
350 $ log 'keyword("test a")'
350 $ log 'keyword("test a")'
351 $ log 'limit(head(), 1)'
351 $ log 'limit(head(), 1)'
352 0
352 0
353 $ log 'matching(6)'
353 $ log 'matching(6)'
354 6
354 6
355 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
355 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
356 6
356 6
357 7
357 7
358
358
359 Testing min and max
359 Testing min and max
360
360
361 max: simple
361 max: simple
362
362
363 $ log 'max(contains(a))'
363 $ log 'max(contains(a))'
364 5
364 5
365
365
366 max: simple on unordered set)
366 max: simple on unordered set)
367
367
368 $ log 'max((4+0+2+5+7) and contains(a))'
368 $ log 'max((4+0+2+5+7) and contains(a))'
369 5
369 5
370
370
371 max: no result
371 max: no result
372
372
373 $ log 'max(contains(stringthatdoesnotappearanywhere))'
373 $ log 'max(contains(stringthatdoesnotappearanywhere))'
374
374
375 max: no result on unordered set
375 max: no result on unordered set
376
376
377 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
377 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
378
378
379 min: simple
379 min: simple
380
380
381 $ log 'min(contains(a))'
381 $ log 'min(contains(a))'
382 0
382 0
383
383
384 min: simple on unordered set
384 min: simple on unordered set
385
385
386 $ log 'min((4+0+2+5+7) and contains(a))'
386 $ log 'min((4+0+2+5+7) and contains(a))'
387 0
387 0
388
388
389 min: empty
389 min: empty
390
390
391 $ log 'min(contains(stringthatdoesnotappearanywhere))'
391 $ log 'min(contains(stringthatdoesnotappearanywhere))'
392
392
393 min: empty on unordered set
393 min: empty on unordered set
394
394
395 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
395 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
396
396
397
397
398 $ log 'merge()'
398 $ log 'merge()'
399 6
399 6
400 $ log 'branchpoint()'
400 $ log 'branchpoint()'
401 1
401 1
402 4
402 4
403 $ log 'modifies(b)'
403 $ log 'modifies(b)'
404 4
404 4
405 $ log 'modifies("path:b")'
405 $ log 'modifies("path:b")'
406 4
406 4
407 $ log 'modifies("*")'
407 $ log 'modifies("*")'
408 4
408 4
409 6
409 6
410 $ log 'modifies("set:modified()")'
410 $ log 'modifies("set:modified()")'
411 4
411 4
412 $ log 'id(5)'
412 $ log 'id(5)'
413 2
413 2
414 $ log 'only(9)'
414 $ log 'only(9)'
415 8
415 8
416 9
416 9
417 $ log 'only(8)'
417 $ log 'only(8)'
418 8
418 8
419 $ log 'only(9, 5)'
419 $ log 'only(9, 5)'
420 2
420 2
421 4
421 4
422 8
422 8
423 9
423 9
424 $ log 'only(7 + 9, 5 + 2)'
424 $ log 'only(7 + 9, 5 + 2)'
425 4
425 4
426 6
426 6
427 7
427 7
428 8
428 8
429 9
429 9
430
430
431 Test empty set input
431 Test empty set input
432 $ log 'only(p2())'
432 $ log 'only(p2())'
433 $ log 'only(p1(), p2())'
433 $ log 'only(p1(), p2())'
434 0
434 0
435 1
435 1
436 2
436 2
437 4
437 4
438 8
438 8
439 9
439 9
440
440
441 Test '%' operator
441 Test '%' operator
442
442
443 $ log '9%'
443 $ log '9%'
444 8
444 8
445 9
445 9
446 $ log '9%5'
446 $ log '9%5'
447 2
447 2
448 4
448 4
449 8
449 8
450 9
450 9
451 $ log '(7 + 9)%(5 + 2)'
451 $ log '(7 + 9)%(5 + 2)'
452 4
452 4
453 6
453 6
454 7
454 7
455 8
455 8
456 9
456 9
457
457
458 Test the order of operations
458 Test the order of operations
459
459
460 $ log '7 + 9%5 + 2'
460 $ log '7 + 9%5 + 2'
461 7
461 7
462 2
462 2
463 4
463 4
464 8
464 8
465 9
465 9
466
466
467 Test explicit numeric revision
467 Test explicit numeric revision
468 $ log 'rev(-2)'
468 $ log 'rev(-2)'
469 $ log 'rev(-1)'
469 $ log 'rev(-1)'
470 -1
470 -1
471 $ log 'rev(0)'
471 $ log 'rev(0)'
472 0
472 0
473 $ log 'rev(9)'
473 $ log 'rev(9)'
474 9
474 9
475 $ log 'rev(10)'
475 $ log 'rev(10)'
476 $ log 'rev(tip)'
476 $ log 'rev(tip)'
477 hg: parse error: rev expects a number
477 hg: parse error: rev expects a number
478 [255]
478 [255]
479
479
480 Test null revision
481 $ log 'ancestors(null)'
482 -1
483
480 $ log 'outgoing()'
484 $ log 'outgoing()'
481 8
485 8
482 9
486 9
483 $ log 'outgoing("../remote1")'
487 $ log 'outgoing("../remote1")'
484 8
488 8
485 9
489 9
486 $ log 'outgoing("../remote2")'
490 $ log 'outgoing("../remote2")'
487 3
491 3
488 5
492 5
489 6
493 6
490 7
494 7
491 9
495 9
492 $ log 'p1(merge())'
496 $ log 'p1(merge())'
493 5
497 5
494 $ log 'p2(merge())'
498 $ log 'p2(merge())'
495 4
499 4
496 $ log 'parents(merge())'
500 $ log 'parents(merge())'
497 4
501 4
498 5
502 5
499 $ log 'p1(branchpoint())'
503 $ log 'p1(branchpoint())'
500 0
504 0
501 2
505 2
502 $ log 'p2(branchpoint())'
506 $ log 'p2(branchpoint())'
503 $ log 'parents(branchpoint())'
507 $ log 'parents(branchpoint())'
504 0
508 0
505 2
509 2
506 $ log 'removes(a)'
510 $ log 'removes(a)'
507 2
511 2
508 6
512 6
509 $ log 'roots(all())'
513 $ log 'roots(all())'
510 0
514 0
511 $ log 'reverse(2 or 3 or 4 or 5)'
515 $ log 'reverse(2 or 3 or 4 or 5)'
512 5
516 5
513 4
517 4
514 3
518 3
515 2
519 2
516 $ log 'reverse(all())'
520 $ log 'reverse(all())'
517 9
521 9
518 8
522 8
519 7
523 7
520 6
524 6
521 5
525 5
522 4
526 4
523 3
527 3
524 2
528 2
525 1
529 1
526 0
530 0
527 $ log 'reverse(all()) & filelog(b)'
531 $ log 'reverse(all()) & filelog(b)'
528 4
532 4
529 1
533 1
530 $ log 'rev(5)'
534 $ log 'rev(5)'
531 5
535 5
532 $ log 'sort(limit(reverse(all()), 3))'
536 $ log 'sort(limit(reverse(all()), 3))'
533 7
537 7
534 8
538 8
535 9
539 9
536 $ log 'sort(2 or 3 or 4 or 5, date)'
540 $ log 'sort(2 or 3 or 4 or 5, date)'
537 2
541 2
538 3
542 3
539 5
543 5
540 4
544 4
541 $ log 'tagged()'
545 $ log 'tagged()'
542 6
546 6
543 $ log 'tag()'
547 $ log 'tag()'
544 6
548 6
545 $ log 'tag(1.0)'
549 $ log 'tag(1.0)'
546 6
550 6
547 $ log 'tag(tip)'
551 $ log 'tag(tip)'
548 9
552 9
549
553
550 test sort revset
554 test sort revset
551 --------------------------------------------
555 --------------------------------------------
552
556
553 test when adding two unordered revsets
557 test when adding two unordered revsets
554
558
555 $ log 'sort(keyword(issue) or modifies(b))'
559 $ log 'sort(keyword(issue) or modifies(b))'
556 4
560 4
557 6
561 6
558
562
559 test when sorting a reversed collection in the same way it is
563 test when sorting a reversed collection in the same way it is
560
564
561 $ log 'sort(reverse(all()), -rev)'
565 $ log 'sort(reverse(all()), -rev)'
562 9
566 9
563 8
567 8
564 7
568 7
565 6
569 6
566 5
570 5
567 4
571 4
568 3
572 3
569 2
573 2
570 1
574 1
571 0
575 0
572
576
573 test when sorting a reversed collection
577 test when sorting a reversed collection
574
578
575 $ log 'sort(reverse(all()), rev)'
579 $ log 'sort(reverse(all()), rev)'
576 0
580 0
577 1
581 1
578 2
582 2
579 3
583 3
580 4
584 4
581 5
585 5
582 6
586 6
583 7
587 7
584 8
588 8
585 9
589 9
586
590
587
591
588 test sorting two sorted collections in different orders
592 test sorting two sorted collections in different orders
589
593
590 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
594 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
591 2
595 2
592 6
596 6
593 8
597 8
594 9
598 9
595
599
596 test sorting two sorted collections in different orders backwards
600 test sorting two sorted collections in different orders backwards
597
601
598 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
602 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
599 9
603 9
600 8
604 8
601 6
605 6
602 2
606 2
603
607
604 test subtracting something from an addset
608 test subtracting something from an addset
605
609
606 $ log '(outgoing() or removes(a)) - removes(a)'
610 $ log '(outgoing() or removes(a)) - removes(a)'
607 8
611 8
608 9
612 9
609
613
610 test intersecting something with an addset
614 test intersecting something with an addset
611
615
612 $ log 'parents(outgoing() or removes(a))'
616 $ log 'parents(outgoing() or removes(a))'
613 1
617 1
614 4
618 4
615 5
619 5
616 8
620 8
617
621
618 test that `or` operation combines elements in the right order:
622 test that `or` operation combines elements in the right order:
619
623
620 $ log '3:4 or 2:5'
624 $ log '3:4 or 2:5'
621 3
625 3
622 4
626 4
623 2
627 2
624 5
628 5
625 $ log '3:4 or 5:2'
629 $ log '3:4 or 5:2'
626 3
630 3
627 4
631 4
628 5
632 5
629 2
633 2
630 $ log 'sort(3:4 or 2:5)'
634 $ log 'sort(3:4 or 2:5)'
631 2
635 2
632 3
636 3
633 4
637 4
634 5
638 5
635 $ log 'sort(3:4 or 5:2)'
639 $ log 'sort(3:4 or 5:2)'
636 2
640 2
637 3
641 3
638 4
642 4
639 5
643 5
640
644
641 check that conversion to only works
645 check that conversion to only works
642 $ try --optimize '::3 - ::1'
646 $ try --optimize '::3 - ::1'
643 (minus
647 (minus
644 (dagrangepre
648 (dagrangepre
645 ('symbol', '3'))
649 ('symbol', '3'))
646 (dagrangepre
650 (dagrangepre
647 ('symbol', '1')))
651 ('symbol', '1')))
648 * optimized:
652 * optimized:
649 (func
653 (func
650 ('symbol', 'only')
654 ('symbol', 'only')
651 (list
655 (list
652 ('symbol', '3')
656 ('symbol', '3')
653 ('symbol', '1')))
657 ('symbol', '1')))
654 3
658 3
655 $ try --optimize 'ancestors(1) - ancestors(3)'
659 $ try --optimize 'ancestors(1) - ancestors(3)'
656 (minus
660 (minus
657 (func
661 (func
658 ('symbol', 'ancestors')
662 ('symbol', 'ancestors')
659 ('symbol', '1'))
663 ('symbol', '1'))
660 (func
664 (func
661 ('symbol', 'ancestors')
665 ('symbol', 'ancestors')
662 ('symbol', '3')))
666 ('symbol', '3')))
663 * optimized:
667 * optimized:
664 (func
668 (func
665 ('symbol', 'only')
669 ('symbol', 'only')
666 (list
670 (list
667 ('symbol', '1')
671 ('symbol', '1')
668 ('symbol', '3')))
672 ('symbol', '3')))
669 $ try --optimize 'not ::2 and ::6'
673 $ try --optimize 'not ::2 and ::6'
670 (and
674 (and
671 (not
675 (not
672 (dagrangepre
676 (dagrangepre
673 ('symbol', '2')))
677 ('symbol', '2')))
674 (dagrangepre
678 (dagrangepre
675 ('symbol', '6')))
679 ('symbol', '6')))
676 * optimized:
680 * optimized:
677 (func
681 (func
678 ('symbol', 'only')
682 ('symbol', 'only')
679 (list
683 (list
680 ('symbol', '6')
684 ('symbol', '6')
681 ('symbol', '2')))
685 ('symbol', '2')))
682 3
686 3
683 4
687 4
684 5
688 5
685 6
689 6
686 $ try --optimize 'ancestors(6) and not ancestors(4)'
690 $ try --optimize 'ancestors(6) and not ancestors(4)'
687 (and
691 (and
688 (func
692 (func
689 ('symbol', 'ancestors')
693 ('symbol', 'ancestors')
690 ('symbol', '6'))
694 ('symbol', '6'))
691 (not
695 (not
692 (func
696 (func
693 ('symbol', 'ancestors')
697 ('symbol', 'ancestors')
694 ('symbol', '4'))))
698 ('symbol', '4'))))
695 * optimized:
699 * optimized:
696 (func
700 (func
697 ('symbol', 'only')
701 ('symbol', 'only')
698 (list
702 (list
699 ('symbol', '6')
703 ('symbol', '6')
700 ('symbol', '4')))
704 ('symbol', '4')))
701 3
705 3
702 5
706 5
703 6
707 6
704
708
705 we can use patterns when searching for tags
709 we can use patterns when searching for tags
706
710
707 $ log 'tag("1..*")'
711 $ log 'tag("1..*")'
708 abort: tag '1..*' does not exist
712 abort: tag '1..*' does not exist
709 [255]
713 [255]
710 $ log 'tag("re:1..*")'
714 $ log 'tag("re:1..*")'
711 6
715 6
712 $ log 'tag("re:[0-9].[0-9]")'
716 $ log 'tag("re:[0-9].[0-9]")'
713 6
717 6
714 $ log 'tag("literal:1.0")'
718 $ log 'tag("literal:1.0")'
715 6
719 6
716 $ log 'tag("re:0..*")'
720 $ log 'tag("re:0..*")'
717
721
718 $ log 'tag(unknown)'
722 $ log 'tag(unknown)'
719 abort: tag 'unknown' does not exist
723 abort: tag 'unknown' does not exist
720 [255]
724 [255]
721 $ log 'branch(unknown)'
725 $ log 'branch(unknown)'
722 abort: unknown revision 'unknown'!
726 abort: unknown revision 'unknown'!
723 [255]
727 [255]
724 $ log 'user(bob)'
728 $ log 'user(bob)'
725 2
729 2
726
730
727 $ log '4::8'
731 $ log '4::8'
728 4
732 4
729 8
733 8
730 $ log '4:8'
734 $ log '4:8'
731 4
735 4
732 5
736 5
733 6
737 6
734 7
738 7
735 8
739 8
736
740
737 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
741 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
738 4
742 4
739 2
743 2
740 5
744 5
741
745
742 $ log 'not 0 and 0:2'
746 $ log 'not 0 and 0:2'
743 1
747 1
744 2
748 2
745 $ log 'not 1 and 0:2'
749 $ log 'not 1 and 0:2'
746 0
750 0
747 2
751 2
748 $ log 'not 2 and 0:2'
752 $ log 'not 2 and 0:2'
749 0
753 0
750 1
754 1
751 $ log '(1 and 2)::'
755 $ log '(1 and 2)::'
752 $ log '(1 and 2):'
756 $ log '(1 and 2):'
753 $ log '(1 and 2):3'
757 $ log '(1 and 2):3'
754 $ log 'sort(head(), -rev)'
758 $ log 'sort(head(), -rev)'
755 9
759 9
756 7
760 7
757 6
761 6
758 5
762 5
759 4
763 4
760 3
764 3
761 2
765 2
762 1
766 1
763 0
767 0
764 $ log '4::8 - 8'
768 $ log '4::8 - 8'
765 4
769 4
766 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
770 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
767 2
771 2
768 3
772 3
769 1
773 1
770
774
771 issue2437
775 issue2437
772
776
773 $ log '3 and p1(5)'
777 $ log '3 and p1(5)'
774 3
778 3
775 $ log '4 and p2(6)'
779 $ log '4 and p2(6)'
776 4
780 4
777 $ log '1 and parents(:2)'
781 $ log '1 and parents(:2)'
778 1
782 1
779 $ log '2 and children(1:)'
783 $ log '2 and children(1:)'
780 2
784 2
781 $ log 'roots(all()) or roots(all())'
785 $ log 'roots(all()) or roots(all())'
782 0
786 0
783 $ hg debugrevspec 'roots(all()) or roots(all())'
787 $ hg debugrevspec 'roots(all()) or roots(all())'
784 0
788 0
785 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
789 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
786 9
790 9
787 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
791 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
788 4
792 4
789
793
790 issue2654: report a parse error if the revset was not completely parsed
794 issue2654: report a parse error if the revset was not completely parsed
791
795
792 $ log '1 OR 2'
796 $ log '1 OR 2'
793 hg: parse error at 2: invalid token
797 hg: parse error at 2: invalid token
794 [255]
798 [255]
795
799
796 or operator should preserve ordering:
800 or operator should preserve ordering:
797 $ log 'reverse(2::4) or tip'
801 $ log 'reverse(2::4) or tip'
798 4
802 4
799 2
803 2
800 9
804 9
801
805
802 parentrevspec
806 parentrevspec
803
807
804 $ log 'merge()^0'
808 $ log 'merge()^0'
805 6
809 6
806 $ log 'merge()^'
810 $ log 'merge()^'
807 5
811 5
808 $ log 'merge()^1'
812 $ log 'merge()^1'
809 5
813 5
810 $ log 'merge()^2'
814 $ log 'merge()^2'
811 4
815 4
812 $ log 'merge()^^'
816 $ log 'merge()^^'
813 3
817 3
814 $ log 'merge()^1^'
818 $ log 'merge()^1^'
815 3
819 3
816 $ log 'merge()^^^'
820 $ log 'merge()^^^'
817 1
821 1
818
822
819 $ log 'merge()~0'
823 $ log 'merge()~0'
820 6
824 6
821 $ log 'merge()~1'
825 $ log 'merge()~1'
822 5
826 5
823 $ log 'merge()~2'
827 $ log 'merge()~2'
824 3
828 3
825 $ log 'merge()~2^1'
829 $ log 'merge()~2^1'
826 1
830 1
827 $ log 'merge()~3'
831 $ log 'merge()~3'
828 1
832 1
829
833
830 $ log '(-3:tip)^'
834 $ log '(-3:tip)^'
831 4
835 4
832 6
836 6
833 8
837 8
834
838
835 $ log 'tip^foo'
839 $ log 'tip^foo'
836 hg: parse error: ^ expects a number 0, 1, or 2
840 hg: parse error: ^ expects a number 0, 1, or 2
837 [255]
841 [255]
838
842
839 multiple revspecs
843 multiple revspecs
840
844
841 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
845 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
842 8
846 8
843 9
847 9
844 4
848 4
845 5
849 5
846 6
850 6
847 7
851 7
848
852
849 test usage in revpair (with "+")
853 test usage in revpair (with "+")
850
854
851 (real pair)
855 (real pair)
852
856
853 $ hg diff -r 'tip^^' -r 'tip'
857 $ hg diff -r 'tip^^' -r 'tip'
854 diff -r 2326846efdab -r 24286f4ae135 .hgtags
858 diff -r 2326846efdab -r 24286f4ae135 .hgtags
855 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
859 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
856 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
860 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
857 @@ -0,0 +1,1 @@
861 @@ -0,0 +1,1 @@
858 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
862 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
859 $ hg diff -r 'tip^^::tip'
863 $ hg diff -r 'tip^^::tip'
860 diff -r 2326846efdab -r 24286f4ae135 .hgtags
864 diff -r 2326846efdab -r 24286f4ae135 .hgtags
861 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
865 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
862 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
866 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
863 @@ -0,0 +1,1 @@
867 @@ -0,0 +1,1 @@
864 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
868 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
865
869
866 (single rev)
870 (single rev)
867
871
868 $ hg diff -r 'tip^' -r 'tip^'
872 $ hg diff -r 'tip^' -r 'tip^'
869 $ hg diff -r 'tip^::tip^ or tip^'
873 $ hg diff -r 'tip^::tip^ or tip^'
870
874
871 (single rev that does not looks like a range)
875 (single rev that does not looks like a range)
872
876
873 $ hg diff -r 'tip^ or tip^'
877 $ hg diff -r 'tip^ or tip^'
874 diff -r d5d0dcbdc4d9 .hgtags
878 diff -r d5d0dcbdc4d9 .hgtags
875 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
879 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
876 +++ b/.hgtags * (glob)
880 +++ b/.hgtags * (glob)
877 @@ -0,0 +1,1 @@
881 @@ -0,0 +1,1 @@
878 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
882 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
879
883
880 (no rev)
884 (no rev)
881
885
882 $ hg diff -r 'author("babar") or author("celeste")'
886 $ hg diff -r 'author("babar") or author("celeste")'
883 abort: empty revision range
887 abort: empty revision range
884 [255]
888 [255]
885
889
886 aliases:
890 aliases:
887
891
888 $ echo '[revsetalias]' >> .hg/hgrc
892 $ echo '[revsetalias]' >> .hg/hgrc
889 $ echo 'm = merge()' >> .hg/hgrc
893 $ echo 'm = merge()' >> .hg/hgrc
890 $ echo 'sincem = descendants(m)' >> .hg/hgrc
894 $ echo 'sincem = descendants(m)' >> .hg/hgrc
891 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
895 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
892 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
896 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
893 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
897 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
894
898
895 $ try m
899 $ try m
896 ('symbol', 'm')
900 ('symbol', 'm')
897 (func
901 (func
898 ('symbol', 'merge')
902 ('symbol', 'merge')
899 None)
903 None)
900 6
904 6
901
905
902 test alias recursion
906 test alias recursion
903
907
904 $ try sincem
908 $ try sincem
905 ('symbol', 'sincem')
909 ('symbol', 'sincem')
906 (func
910 (func
907 ('symbol', 'descendants')
911 ('symbol', 'descendants')
908 (func
912 (func
909 ('symbol', 'merge')
913 ('symbol', 'merge')
910 None))
914 None))
911 6
915 6
912 7
916 7
913
917
914 test infinite recursion
918 test infinite recursion
915
919
916 $ echo 'recurse1 = recurse2' >> .hg/hgrc
920 $ echo 'recurse1 = recurse2' >> .hg/hgrc
917 $ echo 'recurse2 = recurse1' >> .hg/hgrc
921 $ echo 'recurse2 = recurse1' >> .hg/hgrc
918 $ try recurse1
922 $ try recurse1
919 ('symbol', 'recurse1')
923 ('symbol', 'recurse1')
920 hg: parse error: infinite expansion of revset alias "recurse1" detected
924 hg: parse error: infinite expansion of revset alias "recurse1" detected
921 [255]
925 [255]
922
926
923 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
927 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
924 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
928 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
925 $ try "level2(level1(1, 2), 3)"
929 $ try "level2(level1(1, 2), 3)"
926 (func
930 (func
927 ('symbol', 'level2')
931 ('symbol', 'level2')
928 (list
932 (list
929 (func
933 (func
930 ('symbol', 'level1')
934 ('symbol', 'level1')
931 (list
935 (list
932 ('symbol', '1')
936 ('symbol', '1')
933 ('symbol', '2')))
937 ('symbol', '2')))
934 ('symbol', '3')))
938 ('symbol', '3')))
935 (or
939 (or
936 ('symbol', '3')
940 ('symbol', '3')
937 (or
941 (or
938 ('symbol', '1')
942 ('symbol', '1')
939 ('symbol', '2')))
943 ('symbol', '2')))
940 3
944 3
941 1
945 1
942 2
946 2
943
947
944 test nesting and variable passing
948 test nesting and variable passing
945
949
946 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
950 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
947 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
951 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
948 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
952 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
949 $ try 'nested(2:5)'
953 $ try 'nested(2:5)'
950 (func
954 (func
951 ('symbol', 'nested')
955 ('symbol', 'nested')
952 (range
956 (range
953 ('symbol', '2')
957 ('symbol', '2')
954 ('symbol', '5')))
958 ('symbol', '5')))
955 (func
959 (func
956 ('symbol', 'max')
960 ('symbol', 'max')
957 (range
961 (range
958 ('symbol', '2')
962 ('symbol', '2')
959 ('symbol', '5')))
963 ('symbol', '5')))
960 5
964 5
961
965
962 test variable isolation, variable placeholders are rewritten as string
966 test variable isolation, variable placeholders are rewritten as string
963 then parsed and matched again as string. Check they do not leak too
967 then parsed and matched again as string. Check they do not leak too
964 far away.
968 far away.
965
969
966 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
970 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
967 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
971 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
968 $ try 'callinjection(2:5)'
972 $ try 'callinjection(2:5)'
969 (func
973 (func
970 ('symbol', 'callinjection')
974 ('symbol', 'callinjection')
971 (range
975 (range
972 ('symbol', '2')
976 ('symbol', '2')
973 ('symbol', '5')))
977 ('symbol', '5')))
974 (func
978 (func
975 ('symbol', 'descendants')
979 ('symbol', 'descendants')
976 (func
980 (func
977 ('symbol', 'max')
981 ('symbol', 'max')
978 ('string', '$1')))
982 ('string', '$1')))
979 abort: unknown revision '$1'!
983 abort: unknown revision '$1'!
980 [255]
984 [255]
981
985
982 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
986 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
983 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
987 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
984 $ try 'callinjection2(2:5)'
988 $ try 'callinjection2(2:5)'
985 (func
989 (func
986 ('symbol', 'callinjection2')
990 ('symbol', 'callinjection2')
987 (range
991 (range
988 ('symbol', '2')
992 ('symbol', '2')
989 ('symbol', '5')))
993 ('symbol', '5')))
990 abort: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
994 abort: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
991 [255]
995 [255]
992 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
996 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
993 ('symbol', 'tip')
997 ('symbol', 'tip')
994 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
998 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
995 warning: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
999 warning: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
996 9
1000 9
997 >>> data = file('.hg/hgrc', 'rb').read()
1001 >>> data = file('.hg/hgrc', 'rb').read()
998 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1002 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
999
1003
1000 $ try 'tip'
1004 $ try 'tip'
1001 ('symbol', 'tip')
1005 ('symbol', 'tip')
1002 9
1006 9
1003
1007
1004 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1008 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1005 ('symbol', 'tip')
1009 ('symbol', 'tip')
1006 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1010 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1007 9
1011 9
1008
1012
1009 $ try 'd(2:5)'
1013 $ try 'd(2:5)'
1010 (func
1014 (func
1011 ('symbol', 'd')
1015 ('symbol', 'd')
1012 (range
1016 (range
1013 ('symbol', '2')
1017 ('symbol', '2')
1014 ('symbol', '5')))
1018 ('symbol', '5')))
1015 (func
1019 (func
1016 ('symbol', 'reverse')
1020 ('symbol', 'reverse')
1017 (func
1021 (func
1018 ('symbol', 'sort')
1022 ('symbol', 'sort')
1019 (list
1023 (list
1020 (range
1024 (range
1021 ('symbol', '2')
1025 ('symbol', '2')
1022 ('symbol', '5'))
1026 ('symbol', '5'))
1023 ('symbol', 'date'))))
1027 ('symbol', 'date'))))
1024 4
1028 4
1025 5
1029 5
1026 3
1030 3
1027 2
1031 2
1028 $ try 'rs(2 or 3, date)'
1032 $ try 'rs(2 or 3, date)'
1029 (func
1033 (func
1030 ('symbol', 'rs')
1034 ('symbol', 'rs')
1031 (list
1035 (list
1032 (or
1036 (or
1033 ('symbol', '2')
1037 ('symbol', '2')
1034 ('symbol', '3'))
1038 ('symbol', '3'))
1035 ('symbol', 'date')))
1039 ('symbol', 'date')))
1036 (func
1040 (func
1037 ('symbol', 'reverse')
1041 ('symbol', 'reverse')
1038 (func
1042 (func
1039 ('symbol', 'sort')
1043 ('symbol', 'sort')
1040 (list
1044 (list
1041 (or
1045 (or
1042 ('symbol', '2')
1046 ('symbol', '2')
1043 ('symbol', '3'))
1047 ('symbol', '3'))
1044 ('symbol', 'date'))))
1048 ('symbol', 'date'))))
1045 3
1049 3
1046 2
1050 2
1047 $ try 'rs()'
1051 $ try 'rs()'
1048 (func
1052 (func
1049 ('symbol', 'rs')
1053 ('symbol', 'rs')
1050 None)
1054 None)
1051 hg: parse error: invalid number of arguments: 0
1055 hg: parse error: invalid number of arguments: 0
1052 [255]
1056 [255]
1053 $ try 'rs(2)'
1057 $ try 'rs(2)'
1054 (func
1058 (func
1055 ('symbol', 'rs')
1059 ('symbol', 'rs')
1056 ('symbol', '2'))
1060 ('symbol', '2'))
1057 hg: parse error: invalid number of arguments: 1
1061 hg: parse error: invalid number of arguments: 1
1058 [255]
1062 [255]
1059 $ try 'rs(2, data, 7)'
1063 $ try 'rs(2, data, 7)'
1060 (func
1064 (func
1061 ('symbol', 'rs')
1065 ('symbol', 'rs')
1062 (list
1066 (list
1063 (list
1067 (list
1064 ('symbol', '2')
1068 ('symbol', '2')
1065 ('symbol', 'data'))
1069 ('symbol', 'data'))
1066 ('symbol', '7')))
1070 ('symbol', '7')))
1067 hg: parse error: invalid number of arguments: 3
1071 hg: parse error: invalid number of arguments: 3
1068 [255]
1072 [255]
1069 $ try 'rs4(2 or 3, x, x, date)'
1073 $ try 'rs4(2 or 3, x, x, date)'
1070 (func
1074 (func
1071 ('symbol', 'rs4')
1075 ('symbol', 'rs4')
1072 (list
1076 (list
1073 (list
1077 (list
1074 (list
1078 (list
1075 (or
1079 (or
1076 ('symbol', '2')
1080 ('symbol', '2')
1077 ('symbol', '3'))
1081 ('symbol', '3'))
1078 ('symbol', 'x'))
1082 ('symbol', 'x'))
1079 ('symbol', 'x'))
1083 ('symbol', 'x'))
1080 ('symbol', 'date')))
1084 ('symbol', 'date')))
1081 (func
1085 (func
1082 ('symbol', 'reverse')
1086 ('symbol', 'reverse')
1083 (func
1087 (func
1084 ('symbol', 'sort')
1088 ('symbol', 'sort')
1085 (list
1089 (list
1086 (or
1090 (or
1087 ('symbol', '2')
1091 ('symbol', '2')
1088 ('symbol', '3'))
1092 ('symbol', '3'))
1089 ('symbol', 'date'))))
1093 ('symbol', 'date'))))
1090 3
1094 3
1091 2
1095 2
1092
1096
1093 issue2549 - correct optimizations
1097 issue2549 - correct optimizations
1094
1098
1095 $ log 'limit(1 or 2 or 3, 2) and not 2'
1099 $ log 'limit(1 or 2 or 3, 2) and not 2'
1096 1
1100 1
1097 $ log 'max(1 or 2) and not 2'
1101 $ log 'max(1 or 2) and not 2'
1098 $ log 'min(1 or 2) and not 1'
1102 $ log 'min(1 or 2) and not 1'
1099 $ log 'last(1 or 2, 1) and not 2'
1103 $ log 'last(1 or 2, 1) and not 2'
1100
1104
1101 issue4289 - ordering of built-ins
1105 issue4289 - ordering of built-ins
1102 $ hg log -M -q -r 3:2
1106 $ hg log -M -q -r 3:2
1103 3:8528aa5637f2
1107 3:8528aa5637f2
1104 2:5ed5505e9f1c
1108 2:5ed5505e9f1c
1105
1109
1106 test revsets started with 40-chars hash (issue3669)
1110 test revsets started with 40-chars hash (issue3669)
1107
1111
1108 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1112 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1109 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1113 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1110 9
1114 9
1111 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1115 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1112 8
1116 8
1113
1117
1114 test or-ed indirect predicates (issue3775)
1118 test or-ed indirect predicates (issue3775)
1115
1119
1116 $ log '6 or 6^1' | sort
1120 $ log '6 or 6^1' | sort
1117 5
1121 5
1118 6
1122 6
1119 $ log '6^1 or 6' | sort
1123 $ log '6^1 or 6' | sort
1120 5
1124 5
1121 6
1125 6
1122 $ log '4 or 4~1' | sort
1126 $ log '4 or 4~1' | sort
1123 2
1127 2
1124 4
1128 4
1125 $ log '4~1 or 4' | sort
1129 $ log '4~1 or 4' | sort
1126 2
1130 2
1127 4
1131 4
1128 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1132 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1129 0
1133 0
1130 1
1134 1
1131 2
1135 2
1132 3
1136 3
1133 4
1137 4
1134 5
1138 5
1135 6
1139 6
1136 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1140 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1137 0
1141 0
1138 1
1142 1
1139 2
1143 2
1140 3
1144 3
1141 4
1145 4
1142 5
1146 5
1143 6
1147 6
1144
1148
1145 tests for 'remote()' predicate:
1149 tests for 'remote()' predicate:
1146 #. (csets in remote) (id) (remote)
1150 #. (csets in remote) (id) (remote)
1147 1. less than local current branch "default"
1151 1. less than local current branch "default"
1148 2. same with local specified "default"
1152 2. same with local specified "default"
1149 3. more than local specified specified
1153 3. more than local specified specified
1150
1154
1151 $ hg clone --quiet -U . ../remote3
1155 $ hg clone --quiet -U . ../remote3
1152 $ cd ../remote3
1156 $ cd ../remote3
1153 $ hg update -q 7
1157 $ hg update -q 7
1154 $ echo r > r
1158 $ echo r > r
1155 $ hg ci -Aqm 10
1159 $ hg ci -Aqm 10
1156 $ log 'remote()'
1160 $ log 'remote()'
1157 7
1161 7
1158 $ log 'remote("a-b-c-")'
1162 $ log 'remote("a-b-c-")'
1159 2
1163 2
1160 $ cd ../repo
1164 $ cd ../repo
1161 $ log 'remote(".a.b.c.", "../remote3")'
1165 $ log 'remote(".a.b.c.", "../remote3")'
1162
1166
1163 tests for concatenation of strings/symbols by "##"
1167 tests for concatenation of strings/symbols by "##"
1164
1168
1165 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1169 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1166 (_concat
1170 (_concat
1167 (_concat
1171 (_concat
1168 (_concat
1172 (_concat
1169 ('symbol', '278')
1173 ('symbol', '278')
1170 ('string', '5f5'))
1174 ('string', '5f5'))
1171 ('symbol', '1ee'))
1175 ('symbol', '1ee'))
1172 ('string', 'ce5'))
1176 ('string', 'ce5'))
1173 ('string', '2785f51eece5')
1177 ('string', '2785f51eece5')
1174 0
1178 0
1175
1179
1176 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1180 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1177 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1181 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1178 (func
1182 (func
1179 ('symbol', 'cat4')
1183 ('symbol', 'cat4')
1180 (list
1184 (list
1181 (list
1185 (list
1182 (list
1186 (list
1183 ('symbol', '278')
1187 ('symbol', '278')
1184 ('string', '5f5'))
1188 ('string', '5f5'))
1185 ('symbol', '1ee'))
1189 ('symbol', '1ee'))
1186 ('string', 'ce5')))
1190 ('string', 'ce5')))
1187 (_concat
1191 (_concat
1188 (_concat
1192 (_concat
1189 (_concat
1193 (_concat
1190 ('symbol', '278')
1194 ('symbol', '278')
1191 ('string', '5f5'))
1195 ('string', '5f5'))
1192 ('symbol', '1ee'))
1196 ('symbol', '1ee'))
1193 ('string', 'ce5'))
1197 ('string', 'ce5'))
1194 ('string', '2785f51eece5')
1198 ('string', '2785f51eece5')
1195 0
1199 0
1196
1200
1197 (check concatenation in alias nesting)
1201 (check concatenation in alias nesting)
1198
1202
1199 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1203 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1200 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1204 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1201 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1205 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1202 0
1206 0
1203
1207
1204 (check operator priority)
1208 (check operator priority)
1205
1209
1206 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1210 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1207 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1211 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1208 0
1212 0
1209 4
1213 4
1210
1214
1211 $ cd ..
1215 $ cd ..
1212
1216
1213 test author/desc/keyword in problematic encoding
1217 test author/desc/keyword in problematic encoding
1214 # unicode: cp932:
1218 # unicode: cp932:
1215 # u30A2 0x83 0x41(= 'A')
1219 # u30A2 0x83 0x41(= 'A')
1216 # u30C2 0x83 0x61(= 'a')
1220 # u30C2 0x83 0x61(= 'a')
1217
1221
1218 $ hg init problematicencoding
1222 $ hg init problematicencoding
1219 $ cd problematicencoding
1223 $ cd problematicencoding
1220
1224
1221 $ python > setup.sh <<EOF
1225 $ python > setup.sh <<EOF
1222 > print u'''
1226 > print u'''
1223 > echo a > text
1227 > echo a > text
1224 > hg add text
1228 > hg add text
1225 > hg --encoding utf-8 commit -u '\u30A2' -m none
1229 > hg --encoding utf-8 commit -u '\u30A2' -m none
1226 > echo b > text
1230 > echo b > text
1227 > hg --encoding utf-8 commit -u '\u30C2' -m none
1231 > hg --encoding utf-8 commit -u '\u30C2' -m none
1228 > echo c > text
1232 > echo c > text
1229 > hg --encoding utf-8 commit -u none -m '\u30A2'
1233 > hg --encoding utf-8 commit -u none -m '\u30A2'
1230 > echo d > text
1234 > echo d > text
1231 > hg --encoding utf-8 commit -u none -m '\u30C2'
1235 > hg --encoding utf-8 commit -u none -m '\u30C2'
1232 > '''.encode('utf-8')
1236 > '''.encode('utf-8')
1233 > EOF
1237 > EOF
1234 $ sh < setup.sh
1238 $ sh < setup.sh
1235
1239
1236 test in problematic encoding
1240 test in problematic encoding
1237 $ python > test.sh <<EOF
1241 $ python > test.sh <<EOF
1238 > print u'''
1242 > print u'''
1239 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1243 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1240 > echo ====
1244 > echo ====
1241 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1245 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1242 > echo ====
1246 > echo ====
1243 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1247 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1244 > echo ====
1248 > echo ====
1245 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1249 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1246 > echo ====
1250 > echo ====
1247 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1251 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1248 > echo ====
1252 > echo ====
1249 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1253 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1250 > '''.encode('cp932')
1254 > '''.encode('cp932')
1251 > EOF
1255 > EOF
1252 $ sh < test.sh
1256 $ sh < test.sh
1253 0
1257 0
1254 ====
1258 ====
1255 1
1259 1
1256 ====
1260 ====
1257 2
1261 2
1258 ====
1262 ====
1259 3
1263 3
1260 ====
1264 ====
1261 0
1265 0
1262 2
1266 2
1263 ====
1267 ====
1264 1
1268 1
1265 3
1269 3
1266
1270
1267 $ cd ..
1271 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now