##// END OF EJS Templates
revbranchcache: return uncached branchinfo for nullrev (issue4683)...
Yuya Nishihara -
r25266:38117278 stable
parent child Browse files
Show More
@@ -1,439 +1,443 b''
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import bin, hex, nullid, nullrev
8 from node import bin, hex, nullid, nullrev
9 import encoding
9 import encoding
10 import scmutil
10 import scmutil
11 import util
11 import util
12 import time
12 import time
13 from array import array
13 from array import array
14 from struct import calcsize, pack, unpack
14 from struct import calcsize, pack, unpack
15
15
16 def _filename(repo):
16 def _filename(repo):
17 """name of a branchcache file for a given repo or repoview"""
17 """name of a branchcache file for a given repo or repoview"""
18 filename = "cache/branch2"
18 filename = "cache/branch2"
19 if repo.filtername:
19 if repo.filtername:
20 filename = '%s-%s' % (filename, repo.filtername)
20 filename = '%s-%s' % (filename, repo.filtername)
21 return filename
21 return filename
22
22
23 def read(repo):
23 def read(repo):
24 try:
24 try:
25 f = repo.vfs(_filename(repo))
25 f = repo.vfs(_filename(repo))
26 lines = f.read().split('\n')
26 lines = f.read().split('\n')
27 f.close()
27 f.close()
28 except (IOError, OSError):
28 except (IOError, OSError):
29 return None
29 return None
30
30
31 try:
31 try:
32 cachekey = lines.pop(0).split(" ", 2)
32 cachekey = lines.pop(0).split(" ", 2)
33 last, lrev = cachekey[:2]
33 last, lrev = cachekey[:2]
34 last, lrev = bin(last), int(lrev)
34 last, lrev = bin(last), int(lrev)
35 filteredhash = None
35 filteredhash = None
36 if len(cachekey) > 2:
36 if len(cachekey) > 2:
37 filteredhash = bin(cachekey[2])
37 filteredhash = bin(cachekey[2])
38 partial = branchcache(tipnode=last, tiprev=lrev,
38 partial = branchcache(tipnode=last, tiprev=lrev,
39 filteredhash=filteredhash)
39 filteredhash=filteredhash)
40 if not partial.validfor(repo):
40 if not partial.validfor(repo):
41 # invalidate the cache
41 # invalidate the cache
42 raise ValueError('tip differs')
42 raise ValueError('tip differs')
43 for l in lines:
43 for l in lines:
44 if not l:
44 if not l:
45 continue
45 continue
46 node, state, label = l.split(" ", 2)
46 node, state, label = l.split(" ", 2)
47 if state not in 'oc':
47 if state not in 'oc':
48 raise ValueError('invalid branch state')
48 raise ValueError('invalid branch state')
49 label = encoding.tolocal(label.strip())
49 label = encoding.tolocal(label.strip())
50 if not node in repo:
50 if not node in repo:
51 raise ValueError('node %s does not exist' % node)
51 raise ValueError('node %s does not exist' % node)
52 node = bin(node)
52 node = bin(node)
53 partial.setdefault(label, []).append(node)
53 partial.setdefault(label, []).append(node)
54 if state == 'c':
54 if state == 'c':
55 partial._closednodes.add(node)
55 partial._closednodes.add(node)
56 except KeyboardInterrupt:
56 except KeyboardInterrupt:
57 raise
57 raise
58 except Exception, inst:
58 except Exception, inst:
59 if repo.ui.debugflag:
59 if repo.ui.debugflag:
60 msg = 'invalid branchheads cache'
60 msg = 'invalid branchheads cache'
61 if repo.filtername is not None:
61 if repo.filtername is not None:
62 msg += ' (%s)' % repo.filtername
62 msg += ' (%s)' % repo.filtername
63 msg += ': %s\n'
63 msg += ': %s\n'
64 repo.ui.debug(msg % inst)
64 repo.ui.debug(msg % inst)
65 partial = None
65 partial = None
66 return partial
66 return partial
67
67
68 ### Nearest subset relation
68 ### Nearest subset relation
69 # Nearest subset of filter X is a filter Y so that:
69 # Nearest subset of filter X is a filter Y so that:
70 # * Y is included in X,
70 # * Y is included in X,
71 # * X - Y is as small as possible.
71 # * X - Y is as small as possible.
72 # This create and ordering used for branchmap purpose.
72 # This create and ordering used for branchmap purpose.
73 # the ordering may be partial
73 # the ordering may be partial
74 subsettable = {None: 'visible',
74 subsettable = {None: 'visible',
75 'visible': 'served',
75 'visible': 'served',
76 'served': 'immutable',
76 'served': 'immutable',
77 'immutable': 'base'}
77 'immutable': 'base'}
78
78
79 def updatecache(repo):
79 def updatecache(repo):
80 cl = repo.changelog
80 cl = repo.changelog
81 filtername = repo.filtername
81 filtername = repo.filtername
82 partial = repo._branchcaches.get(filtername)
82 partial = repo._branchcaches.get(filtername)
83
83
84 revs = []
84 revs = []
85 if partial is None or not partial.validfor(repo):
85 if partial is None or not partial.validfor(repo):
86 partial = read(repo)
86 partial = read(repo)
87 if partial is None:
87 if partial is None:
88 subsetname = subsettable.get(filtername)
88 subsetname = subsettable.get(filtername)
89 if subsetname is None:
89 if subsetname is None:
90 partial = branchcache()
90 partial = branchcache()
91 else:
91 else:
92 subset = repo.filtered(subsetname)
92 subset = repo.filtered(subsetname)
93 partial = subset.branchmap().copy()
93 partial = subset.branchmap().copy()
94 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
94 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
95 revs.extend(r for r in extrarevs if r <= partial.tiprev)
95 revs.extend(r for r in extrarevs if r <= partial.tiprev)
96 revs.extend(cl.revs(start=partial.tiprev + 1))
96 revs.extend(cl.revs(start=partial.tiprev + 1))
97 if revs:
97 if revs:
98 partial.update(repo, revs)
98 partial.update(repo, revs)
99 partial.write(repo)
99 partial.write(repo)
100
100
101 assert partial.validfor(repo), filtername
101 assert partial.validfor(repo), filtername
102 repo._branchcaches[repo.filtername] = partial
102 repo._branchcaches[repo.filtername] = partial
103
103
104 class branchcache(dict):
104 class branchcache(dict):
105 """A dict like object that hold branches heads cache.
105 """A dict like object that hold branches heads cache.
106
106
107 This cache is used to avoid costly computations to determine all the
107 This cache is used to avoid costly computations to determine all the
108 branch heads of a repo.
108 branch heads of a repo.
109
109
110 The cache is serialized on disk in the following format:
110 The cache is serialized on disk in the following format:
111
111
112 <tip hex node> <tip rev number> [optional filtered repo hex hash]
112 <tip hex node> <tip rev number> [optional filtered repo hex hash]
113 <branch head hex node> <open/closed state> <branch name>
113 <branch head hex node> <open/closed state> <branch name>
114 <branch head hex node> <open/closed state> <branch name>
114 <branch head hex node> <open/closed state> <branch name>
115 ...
115 ...
116
116
117 The first line is used to check if the cache is still valid. If the
117 The first line is used to check if the cache is still valid. If the
118 branch cache is for a filtered repo view, an optional third hash is
118 branch cache is for a filtered repo view, an optional third hash is
119 included that hashes the hashes of all filtered revisions.
119 included that hashes the hashes of all filtered revisions.
120
120
121 The open/closed state is represented by a single letter 'o' or 'c'.
121 The open/closed state is represented by a single letter 'o' or 'c'.
122 This field can be used to avoid changelog reads when determining if a
122 This field can be used to avoid changelog reads when determining if a
123 branch head closes a branch or not.
123 branch head closes a branch or not.
124 """
124 """
125
125
126 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
126 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
127 filteredhash=None, closednodes=None):
127 filteredhash=None, closednodes=None):
128 super(branchcache, self).__init__(entries)
128 super(branchcache, self).__init__(entries)
129 self.tipnode = tipnode
129 self.tipnode = tipnode
130 self.tiprev = tiprev
130 self.tiprev = tiprev
131 self.filteredhash = filteredhash
131 self.filteredhash = filteredhash
132 # closednodes is a set of nodes that close their branch. If the branch
132 # closednodes is a set of nodes that close their branch. If the branch
133 # cache has been updated, it may contain nodes that are no longer
133 # cache has been updated, it may contain nodes that are no longer
134 # heads.
134 # heads.
135 if closednodes is None:
135 if closednodes is None:
136 self._closednodes = set()
136 self._closednodes = set()
137 else:
137 else:
138 self._closednodes = closednodes
138 self._closednodes = closednodes
139
139
140 def validfor(self, repo):
140 def validfor(self, repo):
141 """Is the cache content valid regarding a repo
141 """Is the cache content valid regarding a repo
142
142
143 - False when cached tipnode is unknown or if we detect a strip.
143 - False when cached tipnode is unknown or if we detect a strip.
144 - True when cache is up to date or a subset of current repo."""
144 - True when cache is up to date or a subset of current repo."""
145 try:
145 try:
146 return ((self.tipnode == repo.changelog.node(self.tiprev))
146 return ((self.tipnode == repo.changelog.node(self.tiprev))
147 and (self.filteredhash == \
147 and (self.filteredhash == \
148 scmutil.filteredhash(repo, self.tiprev)))
148 scmutil.filteredhash(repo, self.tiprev)))
149 except IndexError:
149 except IndexError:
150 return False
150 return False
151
151
152 def _branchtip(self, heads):
152 def _branchtip(self, heads):
153 '''Return tuple with last open head in heads and false,
153 '''Return tuple with last open head in heads and false,
154 otherwise return last closed head and true.'''
154 otherwise return last closed head and true.'''
155 tip = heads[-1]
155 tip = heads[-1]
156 closed = True
156 closed = True
157 for h in reversed(heads):
157 for h in reversed(heads):
158 if h not in self._closednodes:
158 if h not in self._closednodes:
159 tip = h
159 tip = h
160 closed = False
160 closed = False
161 break
161 break
162 return tip, closed
162 return tip, closed
163
163
164 def branchtip(self, branch):
164 def branchtip(self, branch):
165 '''Return the tipmost open head on branch head, otherwise return the
165 '''Return the tipmost open head on branch head, otherwise return the
166 tipmost closed head on branch.
166 tipmost closed head on branch.
167 Raise KeyError for unknown branch.'''
167 Raise KeyError for unknown branch.'''
168 return self._branchtip(self[branch])[0]
168 return self._branchtip(self[branch])[0]
169
169
170 def branchheads(self, branch, closed=False):
170 def branchheads(self, branch, closed=False):
171 heads = self[branch]
171 heads = self[branch]
172 if not closed:
172 if not closed:
173 heads = [h for h in heads if h not in self._closednodes]
173 heads = [h for h in heads if h not in self._closednodes]
174 return heads
174 return heads
175
175
176 def iterbranches(self):
176 def iterbranches(self):
177 for bn, heads in self.iteritems():
177 for bn, heads in self.iteritems():
178 yield (bn, heads) + self._branchtip(heads)
178 yield (bn, heads) + self._branchtip(heads)
179
179
180 def copy(self):
180 def copy(self):
181 """return an deep copy of the branchcache object"""
181 """return an deep copy of the branchcache object"""
182 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
182 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
183 self._closednodes)
183 self._closednodes)
184
184
185 def write(self, repo):
185 def write(self, repo):
186 try:
186 try:
187 f = repo.vfs(_filename(repo), "w", atomictemp=True)
187 f = repo.vfs(_filename(repo), "w", atomictemp=True)
188 cachekey = [hex(self.tipnode), str(self.tiprev)]
188 cachekey = [hex(self.tipnode), str(self.tiprev)]
189 if self.filteredhash is not None:
189 if self.filteredhash is not None:
190 cachekey.append(hex(self.filteredhash))
190 cachekey.append(hex(self.filteredhash))
191 f.write(" ".join(cachekey) + '\n')
191 f.write(" ".join(cachekey) + '\n')
192 nodecount = 0
192 nodecount = 0
193 for label, nodes in sorted(self.iteritems()):
193 for label, nodes in sorted(self.iteritems()):
194 for node in nodes:
194 for node in nodes:
195 nodecount += 1
195 nodecount += 1
196 if node in self._closednodes:
196 if node in self._closednodes:
197 state = 'c'
197 state = 'c'
198 else:
198 else:
199 state = 'o'
199 state = 'o'
200 f.write("%s %s %s\n" % (hex(node), state,
200 f.write("%s %s %s\n" % (hex(node), state,
201 encoding.fromlocal(label)))
201 encoding.fromlocal(label)))
202 f.close()
202 f.close()
203 repo.ui.log('branchcache',
203 repo.ui.log('branchcache',
204 'wrote %s branch cache with %d labels and %d nodes\n',
204 'wrote %s branch cache with %d labels and %d nodes\n',
205 repo.filtername, len(self), nodecount)
205 repo.filtername, len(self), nodecount)
206 except (IOError, OSError, util.Abort), inst:
206 except (IOError, OSError, util.Abort), inst:
207 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
207 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
208 # Abort may be raise by read only opener
208 # Abort may be raise by read only opener
209 pass
209 pass
210
210
211 def update(self, repo, revgen):
211 def update(self, repo, revgen):
212 """Given a branchhead cache, self, that may have extra nodes or be
212 """Given a branchhead cache, self, that may have extra nodes or be
213 missing heads, and a generator of nodes that are strictly a superset of
213 missing heads, and a generator of nodes that are strictly a superset of
214 heads missing, this function updates self to be correct.
214 heads missing, this function updates self to be correct.
215 """
215 """
216 starttime = time.time()
216 starttime = time.time()
217 cl = repo.changelog
217 cl = repo.changelog
218 # collect new branch entries
218 # collect new branch entries
219 newbranches = {}
219 newbranches = {}
220 getbranchinfo = repo.revbranchcache().branchinfo
220 getbranchinfo = repo.revbranchcache().branchinfo
221 for r in revgen:
221 for r in revgen:
222 branch, closesbranch = getbranchinfo(r)
222 branch, closesbranch = getbranchinfo(r)
223 newbranches.setdefault(branch, []).append(r)
223 newbranches.setdefault(branch, []).append(r)
224 if closesbranch:
224 if closesbranch:
225 self._closednodes.add(cl.node(r))
225 self._closednodes.add(cl.node(r))
226
226
227 # fetch current topological heads to speed up filtering
227 # fetch current topological heads to speed up filtering
228 topoheads = set(cl.headrevs())
228 topoheads = set(cl.headrevs())
229
229
230 # if older branchheads are reachable from new ones, they aren't
230 # if older branchheads are reachable from new ones, they aren't
231 # really branchheads. Note checking parents is insufficient:
231 # really branchheads. Note checking parents is insufficient:
232 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
232 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
233 for branch, newheadrevs in newbranches.iteritems():
233 for branch, newheadrevs in newbranches.iteritems():
234 bheads = self.setdefault(branch, [])
234 bheads = self.setdefault(branch, [])
235 bheadset = set(cl.rev(node) for node in bheads)
235 bheadset = set(cl.rev(node) for node in bheads)
236
236
237 # This have been tested True on all internal usage of this function.
237 # This have been tested True on all internal usage of this function.
238 # run it again in case of doubt
238 # run it again in case of doubt
239 # assert not (set(bheadrevs) & set(newheadrevs))
239 # assert not (set(bheadrevs) & set(newheadrevs))
240 newheadrevs.sort()
240 newheadrevs.sort()
241 bheadset.update(newheadrevs)
241 bheadset.update(newheadrevs)
242
242
243 # This prunes out two kinds of heads - heads that are superseded by
243 # This prunes out two kinds of heads - heads that are superseded by
244 # a head in newheadrevs, and newheadrevs that are not heads because
244 # a head in newheadrevs, and newheadrevs that are not heads because
245 # an existing head is their descendant.
245 # an existing head is their descendant.
246 uncertain = bheadset - topoheads
246 uncertain = bheadset - topoheads
247 if uncertain:
247 if uncertain:
248 floorrev = min(uncertain)
248 floorrev = min(uncertain)
249 ancestors = set(cl.ancestors(newheadrevs, floorrev))
249 ancestors = set(cl.ancestors(newheadrevs, floorrev))
250 bheadset -= ancestors
250 bheadset -= ancestors
251 bheadrevs = sorted(bheadset)
251 bheadrevs = sorted(bheadset)
252 self[branch] = [cl.node(rev) for rev in bheadrevs]
252 self[branch] = [cl.node(rev) for rev in bheadrevs]
253 tiprev = bheadrevs[-1]
253 tiprev = bheadrevs[-1]
254 if tiprev > self.tiprev:
254 if tiprev > self.tiprev:
255 self.tipnode = cl.node(tiprev)
255 self.tipnode = cl.node(tiprev)
256 self.tiprev = tiprev
256 self.tiprev = tiprev
257
257
258 if not self.validfor(repo):
258 if not self.validfor(repo):
259 # cache key are not valid anymore
259 # cache key are not valid anymore
260 self.tipnode = nullid
260 self.tipnode = nullid
261 self.tiprev = nullrev
261 self.tiprev = nullrev
262 for heads in self.values():
262 for heads in self.values():
263 tiprev = max(cl.rev(node) for node in heads)
263 tiprev = max(cl.rev(node) for node in heads)
264 if tiprev > self.tiprev:
264 if tiprev > self.tiprev:
265 self.tipnode = cl.node(tiprev)
265 self.tipnode = cl.node(tiprev)
266 self.tiprev = tiprev
266 self.tiprev = tiprev
267 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
267 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
268
268
269 duration = time.time() - starttime
269 duration = time.time() - starttime
270 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
270 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
271 repo.filtername, duration)
271 repo.filtername, duration)
272
272
273 # Revision branch info cache
273 # Revision branch info cache
274
274
275 _rbcversion = '-v1'
275 _rbcversion = '-v1'
276 _rbcnames = 'cache/rbc-names' + _rbcversion
276 _rbcnames = 'cache/rbc-names' + _rbcversion
277 _rbcrevs = 'cache/rbc-revs' + _rbcversion
277 _rbcrevs = 'cache/rbc-revs' + _rbcversion
278 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
278 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
279 _rbcrecfmt = '>4sI'
279 _rbcrecfmt = '>4sI'
280 _rbcrecsize = calcsize(_rbcrecfmt)
280 _rbcrecsize = calcsize(_rbcrecfmt)
281 _rbcnodelen = 4
281 _rbcnodelen = 4
282 _rbcbranchidxmask = 0x7fffffff
282 _rbcbranchidxmask = 0x7fffffff
283 _rbccloseflag = 0x80000000
283 _rbccloseflag = 0x80000000
284
284
285 class revbranchcache(object):
285 class revbranchcache(object):
286 """Persistent cache, mapping from revision number to branch name and close.
286 """Persistent cache, mapping from revision number to branch name and close.
287 This is a low level cache, independent of filtering.
287 This is a low level cache, independent of filtering.
288
288
289 Branch names are stored in rbc-names in internal encoding separated by 0.
289 Branch names are stored in rbc-names in internal encoding separated by 0.
290 rbc-names is append-only, and each branch name is only stored once and will
290 rbc-names is append-only, and each branch name is only stored once and will
291 thus have a unique index.
291 thus have a unique index.
292
292
293 The branch info for each revision is stored in rbc-revs as constant size
293 The branch info for each revision is stored in rbc-revs as constant size
294 records. The whole file is read into memory, but it is only 'parsed' on
294 records. The whole file is read into memory, but it is only 'parsed' on
295 demand. The file is usually append-only but will be truncated if repo
295 demand. The file is usually append-only but will be truncated if repo
296 modification is detected.
296 modification is detected.
297 The record for each revision contains the first 4 bytes of the
297 The record for each revision contains the first 4 bytes of the
298 corresponding node hash, and the record is only used if it still matches.
298 corresponding node hash, and the record is only used if it still matches.
299 Even a completely trashed rbc-revs fill thus still give the right result
299 Even a completely trashed rbc-revs fill thus still give the right result
300 while converging towards full recovery ... assuming no incorrectly matching
300 while converging towards full recovery ... assuming no incorrectly matching
301 node hashes.
301 node hashes.
302 The record also contains 4 bytes where 31 bits contains the index of the
302 The record also contains 4 bytes where 31 bits contains the index of the
303 branch and the last bit indicate that it is a branch close commit.
303 branch and the last bit indicate that it is a branch close commit.
304 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
304 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
305 and will grow with it but be 1/8th of its size.
305 and will grow with it but be 1/8th of its size.
306 """
306 """
307
307
308 def __init__(self, repo, readonly=True):
308 def __init__(self, repo, readonly=True):
309 assert repo.filtername is None
309 assert repo.filtername is None
310 self._repo = repo
310 self._repo = repo
311 self._names = [] # branch names in local encoding with static index
311 self._names = [] # branch names in local encoding with static index
312 self._rbcrevs = array('c') # structs of type _rbcrecfmt
312 self._rbcrevs = array('c') # structs of type _rbcrecfmt
313 self._rbcsnameslen = 0
313 self._rbcsnameslen = 0
314 try:
314 try:
315 bndata = repo.vfs.read(_rbcnames)
315 bndata = repo.vfs.read(_rbcnames)
316 self._rbcsnameslen = len(bndata) # for verification before writing
316 self._rbcsnameslen = len(bndata) # for verification before writing
317 self._names = [encoding.tolocal(bn) for bn in bndata.split('\0')]
317 self._names = [encoding.tolocal(bn) for bn in bndata.split('\0')]
318 except (IOError, OSError), inst:
318 except (IOError, OSError), inst:
319 if readonly:
319 if readonly:
320 # don't try to use cache - fall back to the slow path
320 # don't try to use cache - fall back to the slow path
321 self.branchinfo = self._branchinfo
321 self.branchinfo = self._branchinfo
322
322
323 if self._names:
323 if self._names:
324 try:
324 try:
325 data = repo.vfs.read(_rbcrevs)
325 data = repo.vfs.read(_rbcrevs)
326 self._rbcrevs.fromstring(data)
326 self._rbcrevs.fromstring(data)
327 except (IOError, OSError), inst:
327 except (IOError, OSError), inst:
328 repo.ui.debug("couldn't read revision branch cache: %s\n" %
328 repo.ui.debug("couldn't read revision branch cache: %s\n" %
329 inst)
329 inst)
330 # remember number of good records on disk
330 # remember number of good records on disk
331 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
331 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
332 len(repo.changelog))
332 len(repo.changelog))
333 if self._rbcrevslen == 0:
333 if self._rbcrevslen == 0:
334 self._names = []
334 self._names = []
335 self._rbcnamescount = len(self._names) # number of good names on disk
335 self._rbcnamescount = len(self._names) # number of good names on disk
336 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
336 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
337
337
338 def branchinfo(self, rev):
338 def branchinfo(self, rev):
339 """Return branch name and close flag for rev, using and updating
339 """Return branch name and close flag for rev, using and updating
340 persistent cache."""
340 persistent cache."""
341 changelog = self._repo.changelog
341 changelog = self._repo.changelog
342 rbcrevidx = rev * _rbcrecsize
342 rbcrevidx = rev * _rbcrecsize
343
343
344 # avoid negative index, changelog.read(nullrev) is fast without cache
345 if rev == nullrev:
346 return changelog.branchinfo(rev)
347
344 # if requested rev is missing, add and populate all missing revs
348 # if requested rev is missing, add and populate all missing revs
345 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
349 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
346 self._rbcrevs.extend('\0' * (len(changelog) * _rbcrecsize -
350 self._rbcrevs.extend('\0' * (len(changelog) * _rbcrecsize -
347 len(self._rbcrevs)))
351 len(self._rbcrevs)))
348
352
349 # fast path: extract data from cache, use it if node is matching
353 # fast path: extract data from cache, use it if node is matching
350 reponode = changelog.node(rev)[:_rbcnodelen]
354 reponode = changelog.node(rev)[:_rbcnodelen]
351 cachenode, branchidx = unpack(
355 cachenode, branchidx = unpack(
352 _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize))
356 _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize))
353 close = bool(branchidx & _rbccloseflag)
357 close = bool(branchidx & _rbccloseflag)
354 if close:
358 if close:
355 branchidx &= _rbcbranchidxmask
359 branchidx &= _rbcbranchidxmask
356 if cachenode == '\0\0\0\0':
360 if cachenode == '\0\0\0\0':
357 pass
361 pass
358 elif cachenode == reponode:
362 elif cachenode == reponode:
359 return self._names[branchidx], close
363 return self._names[branchidx], close
360 else:
364 else:
361 # rev/node map has changed, invalidate the cache from here up
365 # rev/node map has changed, invalidate the cache from here up
362 truncate = rbcrevidx + _rbcrecsize
366 truncate = rbcrevidx + _rbcrecsize
363 del self._rbcrevs[truncate:]
367 del self._rbcrevs[truncate:]
364 self._rbcrevslen = min(self._rbcrevslen, truncate)
368 self._rbcrevslen = min(self._rbcrevslen, truncate)
365
369
366 # fall back to slow path and make sure it will be written to disk
370 # fall back to slow path and make sure it will be written to disk
367 return self._branchinfo(rev)
371 return self._branchinfo(rev)
368
372
369 def _branchinfo(self, rev):
373 def _branchinfo(self, rev):
370 """Retrieve branch info from changelog and update _rbcrevs"""
374 """Retrieve branch info from changelog and update _rbcrevs"""
371 changelog = self._repo.changelog
375 changelog = self._repo.changelog
372 b, close = changelog.branchinfo(rev)
376 b, close = changelog.branchinfo(rev)
373 if b in self._namesreverse:
377 if b in self._namesreverse:
374 branchidx = self._namesreverse[b]
378 branchidx = self._namesreverse[b]
375 else:
379 else:
376 branchidx = len(self._names)
380 branchidx = len(self._names)
377 self._names.append(b)
381 self._names.append(b)
378 self._namesreverse[b] = branchidx
382 self._namesreverse[b] = branchidx
379 reponode = changelog.node(rev)
383 reponode = changelog.node(rev)
380 if close:
384 if close:
381 branchidx |= _rbccloseflag
385 branchidx |= _rbccloseflag
382 self._setcachedata(rev, reponode, branchidx)
386 self._setcachedata(rev, reponode, branchidx)
383 return b, close
387 return b, close
384
388
385 def _setcachedata(self, rev, node, branchidx):
389 def _setcachedata(self, rev, node, branchidx):
386 """Writes the node's branch data to the in-memory cache data."""
390 """Writes the node's branch data to the in-memory cache data."""
387 rbcrevidx = rev * _rbcrecsize
391 rbcrevidx = rev * _rbcrecsize
388 rec = array('c')
392 rec = array('c')
389 rec.fromstring(pack(_rbcrecfmt, node, branchidx))
393 rec.fromstring(pack(_rbcrecfmt, node, branchidx))
390 self._rbcrevs[rbcrevidx:rbcrevidx + _rbcrecsize] = rec
394 self._rbcrevs[rbcrevidx:rbcrevidx + _rbcrecsize] = rec
391 self._rbcrevslen = min(self._rbcrevslen, rev)
395 self._rbcrevslen = min(self._rbcrevslen, rev)
392
396
393 tr = self._repo.currenttransaction()
397 tr = self._repo.currenttransaction()
394 if tr:
398 if tr:
395 tr.addfinalize('write-revbranchcache', self.write)
399 tr.addfinalize('write-revbranchcache', self.write)
396
400
397 def write(self, tr=None):
401 def write(self, tr=None):
398 """Save branch cache if it is dirty."""
402 """Save branch cache if it is dirty."""
399 repo = self._repo
403 repo = self._repo
400 if self._rbcnamescount < len(self._names):
404 if self._rbcnamescount < len(self._names):
401 try:
405 try:
402 if self._rbcnamescount != 0:
406 if self._rbcnamescount != 0:
403 f = repo.vfs.open(_rbcnames, 'ab')
407 f = repo.vfs.open(_rbcnames, 'ab')
404 if f.tell() == self._rbcsnameslen:
408 if f.tell() == self._rbcsnameslen:
405 f.write('\0')
409 f.write('\0')
406 else:
410 else:
407 f.close()
411 f.close()
408 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
412 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
409 self._rbcnamescount = 0
413 self._rbcnamescount = 0
410 self._rbcrevslen = 0
414 self._rbcrevslen = 0
411 if self._rbcnamescount == 0:
415 if self._rbcnamescount == 0:
412 f = repo.vfs.open(_rbcnames, 'wb')
416 f = repo.vfs.open(_rbcnames, 'wb')
413 f.write('\0'.join(encoding.fromlocal(b)
417 f.write('\0'.join(encoding.fromlocal(b)
414 for b in self._names[self._rbcnamescount:]))
418 for b in self._names[self._rbcnamescount:]))
415 self._rbcsnameslen = f.tell()
419 self._rbcsnameslen = f.tell()
416 f.close()
420 f.close()
417 except (IOError, OSError, util.Abort), inst:
421 except (IOError, OSError, util.Abort), inst:
418 repo.ui.debug("couldn't write revision branch cache names: "
422 repo.ui.debug("couldn't write revision branch cache names: "
419 "%s\n" % inst)
423 "%s\n" % inst)
420 return
424 return
421 self._rbcnamescount = len(self._names)
425 self._rbcnamescount = len(self._names)
422
426
423 start = self._rbcrevslen * _rbcrecsize
427 start = self._rbcrevslen * _rbcrecsize
424 if start != len(self._rbcrevs):
428 if start != len(self._rbcrevs):
425 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
429 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
426 try:
430 try:
427 f = repo.vfs.open(_rbcrevs, 'ab')
431 f = repo.vfs.open(_rbcrevs, 'ab')
428 if f.tell() != start:
432 if f.tell() != start:
429 repo.ui.debug("truncating %s to %s\n" % (_rbcrevs, start))
433 repo.ui.debug("truncating %s to %s\n" % (_rbcrevs, start))
430 f.seek(start)
434 f.seek(start)
431 f.truncate()
435 f.truncate()
432 end = revs * _rbcrecsize
436 end = revs * _rbcrecsize
433 f.write(self._rbcrevs[start:end])
437 f.write(self._rbcrevs[start:end])
434 f.close()
438 f.close()
435 except (IOError, OSError, util.Abort), inst:
439 except (IOError, OSError, util.Abort), inst:
436 repo.ui.debug("couldn't write revision branch cache: %s\n" %
440 repo.ui.debug("couldn't write revision branch cache: %s\n" %
437 inst)
441 inst)
438 return
442 return
439 self._rbcrevslen = revs
443 self._rbcrevslen = revs
@@ -1,1674 +1,1682 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug "$@"
5 > hg debugrevspec --debug "$@"
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 (branches are permanent and global, did you want a bookmark?)
18 (branches are permanent and global, did you want a bookmark?)
19 $ hg ci -Aqm0
19 $ hg ci -Aqm0
20
20
21 $ echo b > b
21 $ echo b > b
22 $ hg branch b
22 $ hg branch b
23 marked working directory as branch b
23 marked working directory as branch b
24 (branches are permanent and global, did you want a bookmark?)
24 (branches are permanent and global, did you want a bookmark?)
25 $ hg ci -Aqm1
25 $ hg ci -Aqm1
26
26
27 $ rm a
27 $ rm a
28 $ hg branch a-b-c-
28 $ hg branch a-b-c-
29 marked working directory as branch a-b-c-
29 marked working directory as branch a-b-c-
30 (branches are permanent and global, did you want a bookmark?)
30 (branches are permanent and global, did you want a bookmark?)
31 $ hg ci -Aqm2 -u Bob
31 $ hg ci -Aqm2 -u Bob
32
32
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
34 2
34 2
35 $ hg log -r "extra('branch')" --template '{rev}\n'
35 $ hg log -r "extra('branch')" --template '{rev}\n'
36 0
36 0
37 1
37 1
38 2
38 2
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
40 0 a
40 0 a
41 2 a-b-c-
41 2 a-b-c-
42
42
43 $ hg co 1
43 $ hg co 1
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch +a+b+c+
45 $ hg branch +a+b+c+
46 marked working directory as branch +a+b+c+
46 marked working directory as branch +a+b+c+
47 (branches are permanent and global, did you want a bookmark?)
47 (branches are permanent and global, did you want a bookmark?)
48 $ hg ci -Aqm3
48 $ hg ci -Aqm3
49
49
50 $ hg co 2 # interleave
50 $ hg co 2 # interleave
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
52 $ echo bb > b
52 $ echo bb > b
53 $ hg branch -- -a-b-c-
53 $ hg branch -- -a-b-c-
54 marked working directory as branch -a-b-c-
54 marked working directory as branch -a-b-c-
55 (branches are permanent and global, did you want a bookmark?)
55 (branches are permanent and global, did you want a bookmark?)
56 $ hg ci -Aqm4 -d "May 12 2005"
56 $ hg ci -Aqm4 -d "May 12 2005"
57
57
58 $ hg co 3
58 $ hg co 3
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg branch !a/b/c/
60 $ hg branch !a/b/c/
61 marked working directory as branch !a/b/c/
61 marked working directory as branch !a/b/c/
62 (branches are permanent and global, did you want a bookmark?)
62 (branches are permanent and global, did you want a bookmark?)
63 $ hg ci -Aqm"5 bug"
63 $ hg ci -Aqm"5 bug"
64
64
65 $ hg merge 4
65 $ hg merge 4
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
67 (branch merge, don't forget to commit)
67 (branch merge, don't forget to commit)
68 $ hg branch _a_b_c_
68 $ hg branch _a_b_c_
69 marked working directory as branch _a_b_c_
69 marked working directory as branch _a_b_c_
70 (branches are permanent and global, did you want a bookmark?)
70 (branches are permanent and global, did you want a bookmark?)
71 $ hg ci -Aqm"6 issue619"
71 $ hg ci -Aqm"6 issue619"
72
72
73 $ hg branch .a.b.c.
73 $ hg branch .a.b.c.
74 marked working directory as branch .a.b.c.
74 marked working directory as branch .a.b.c.
75 (branches are permanent and global, did you want a bookmark?)
75 (branches are permanent and global, did you want a bookmark?)
76 $ hg ci -Aqm7
76 $ hg ci -Aqm7
77
77
78 $ hg branch all
78 $ hg branch all
79 marked working directory as branch all
79 marked working directory as branch all
80 (branches are permanent and global, did you want a bookmark?)
80 (branches are permanent and global, did you want a bookmark?)
81
81
82 $ hg co 4
82 $ hg co 4
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ hg branch Γ©
84 $ hg branch Γ©
85 marked working directory as branch \xc3\xa9 (esc)
85 marked working directory as branch \xc3\xa9 (esc)
86 (branches are permanent and global, did you want a bookmark?)
86 (branches are permanent and global, did you want a bookmark?)
87 $ hg ci -Aqm9
87 $ hg ci -Aqm9
88
88
89 $ hg tag -r6 1.0
89 $ hg tag -r6 1.0
90 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
90 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
91
91
92 $ hg clone --quiet -U -r 7 . ../remote1
92 $ hg clone --quiet -U -r 7 . ../remote1
93 $ hg clone --quiet -U -r 8 . ../remote2
93 $ hg clone --quiet -U -r 8 . ../remote2
94 $ echo "[paths]" >> .hg/hgrc
94 $ echo "[paths]" >> .hg/hgrc
95 $ echo "default = ../remote1" >> .hg/hgrc
95 $ echo "default = ../remote1" >> .hg/hgrc
96
96
97 trivial
97 trivial
98
98
99 $ try 0:1
99 $ try 0:1
100 (range
100 (range
101 ('symbol', '0')
101 ('symbol', '0')
102 ('symbol', '1'))
102 ('symbol', '1'))
103 * set:
103 * set:
104 <spanset+ 0:1>
104 <spanset+ 0:1>
105 0
105 0
106 1
106 1
107 $ try 3::6
107 $ try 3::6
108 (dagrange
108 (dagrange
109 ('symbol', '3')
109 ('symbol', '3')
110 ('symbol', '6'))
110 ('symbol', '6'))
111 * set:
111 * set:
112 <baseset [3, 5, 6]>
112 <baseset [3, 5, 6]>
113 3
113 3
114 5
114 5
115 6
115 6
116 $ try '0|1|2'
116 $ try '0|1|2'
117 (or
117 (or
118 (or
118 (or
119 ('symbol', '0')
119 ('symbol', '0')
120 ('symbol', '1'))
120 ('symbol', '1'))
121 ('symbol', '2'))
121 ('symbol', '2'))
122 * set:
122 * set:
123 <addset
123 <addset
124 <addset
124 <addset
125 <baseset [0]>,
125 <baseset [0]>,
126 <baseset [1]>>,
126 <baseset [1]>>,
127 <baseset [2]>>
127 <baseset [2]>>
128 0
128 0
129 1
129 1
130 2
130 2
131
131
132 names that should work without quoting
132 names that should work without quoting
133
133
134 $ try a
134 $ try a
135 ('symbol', 'a')
135 ('symbol', 'a')
136 * set:
136 * set:
137 <baseset [0]>
137 <baseset [0]>
138 0
138 0
139 $ try b-a
139 $ try b-a
140 (minus
140 (minus
141 ('symbol', 'b')
141 ('symbol', 'b')
142 ('symbol', 'a'))
142 ('symbol', 'a'))
143 * set:
143 * set:
144 <filteredset
144 <filteredset
145 <baseset [1]>>
145 <baseset [1]>>
146 1
146 1
147 $ try _a_b_c_
147 $ try _a_b_c_
148 ('symbol', '_a_b_c_')
148 ('symbol', '_a_b_c_')
149 * set:
149 * set:
150 <baseset [6]>
150 <baseset [6]>
151 6
151 6
152 $ try _a_b_c_-a
152 $ try _a_b_c_-a
153 (minus
153 (minus
154 ('symbol', '_a_b_c_')
154 ('symbol', '_a_b_c_')
155 ('symbol', 'a'))
155 ('symbol', 'a'))
156 * set:
156 * set:
157 <filteredset
157 <filteredset
158 <baseset [6]>>
158 <baseset [6]>>
159 6
159 6
160 $ try .a.b.c.
160 $ try .a.b.c.
161 ('symbol', '.a.b.c.')
161 ('symbol', '.a.b.c.')
162 * set:
162 * set:
163 <baseset [7]>
163 <baseset [7]>
164 7
164 7
165 $ try .a.b.c.-a
165 $ try .a.b.c.-a
166 (minus
166 (minus
167 ('symbol', '.a.b.c.')
167 ('symbol', '.a.b.c.')
168 ('symbol', 'a'))
168 ('symbol', 'a'))
169 * set:
169 * set:
170 <filteredset
170 <filteredset
171 <baseset [7]>>
171 <baseset [7]>>
172 7
172 7
173 $ try -- '-a-b-c-' # complains
173 $ try -- '-a-b-c-' # complains
174 hg: parse error at 7: not a prefix: end
174 hg: parse error at 7: not a prefix: end
175 [255]
175 [255]
176 $ log -a-b-c- # succeeds with fallback
176 $ log -a-b-c- # succeeds with fallback
177 4
177 4
178
178
179 $ try -- -a-b-c--a # complains
179 $ try -- -a-b-c--a # complains
180 (minus
180 (minus
181 (minus
181 (minus
182 (minus
182 (minus
183 (negate
183 (negate
184 ('symbol', 'a'))
184 ('symbol', 'a'))
185 ('symbol', 'b'))
185 ('symbol', 'b'))
186 ('symbol', 'c'))
186 ('symbol', 'c'))
187 (negate
187 (negate
188 ('symbol', 'a')))
188 ('symbol', 'a')))
189 abort: unknown revision '-a'!
189 abort: unknown revision '-a'!
190 [255]
190 [255]
191 $ try Γ©
191 $ try Γ©
192 ('symbol', '\xc3\xa9')
192 ('symbol', '\xc3\xa9')
193 * set:
193 * set:
194 <baseset [9]>
194 <baseset [9]>
195 9
195 9
196
196
197 no quoting needed
197 no quoting needed
198
198
199 $ log ::a-b-c-
199 $ log ::a-b-c-
200 0
200 0
201 1
201 1
202 2
202 2
203
203
204 quoting needed
204 quoting needed
205
205
206 $ try '"-a-b-c-"-a'
206 $ try '"-a-b-c-"-a'
207 (minus
207 (minus
208 ('string', '-a-b-c-')
208 ('string', '-a-b-c-')
209 ('symbol', 'a'))
209 ('symbol', 'a'))
210 * set:
210 * set:
211 <filteredset
211 <filteredset
212 <baseset [4]>>
212 <baseset [4]>>
213 4
213 4
214
214
215 $ log '1 or 2'
215 $ log '1 or 2'
216 1
216 1
217 2
217 2
218 $ log '1|2'
218 $ log '1|2'
219 1
219 1
220 2
220 2
221 $ log '1 and 2'
221 $ log '1 and 2'
222 $ log '1&2'
222 $ log '1&2'
223 $ try '1&2|3' # precedence - and is higher
223 $ try '1&2|3' # precedence - and is higher
224 (or
224 (or
225 (and
225 (and
226 ('symbol', '1')
226 ('symbol', '1')
227 ('symbol', '2'))
227 ('symbol', '2'))
228 ('symbol', '3'))
228 ('symbol', '3'))
229 * set:
229 * set:
230 <addset
230 <addset
231 <baseset []>,
231 <baseset []>,
232 <baseset [3]>>
232 <baseset [3]>>
233 3
233 3
234 $ try '1|2&3'
234 $ try '1|2&3'
235 (or
235 (or
236 ('symbol', '1')
236 ('symbol', '1')
237 (and
237 (and
238 ('symbol', '2')
238 ('symbol', '2')
239 ('symbol', '3')))
239 ('symbol', '3')))
240 * set:
240 * set:
241 <addset
241 <addset
242 <baseset [1]>,
242 <baseset [1]>,
243 <baseset []>>
243 <baseset []>>
244 1
244 1
245 $ try '1&2&3' # associativity
245 $ try '1&2&3' # associativity
246 (and
246 (and
247 (and
247 (and
248 ('symbol', '1')
248 ('symbol', '1')
249 ('symbol', '2'))
249 ('symbol', '2'))
250 ('symbol', '3'))
250 ('symbol', '3'))
251 * set:
251 * set:
252 <baseset []>
252 <baseset []>
253 $ try '1|(2|3)'
253 $ try '1|(2|3)'
254 (or
254 (or
255 ('symbol', '1')
255 ('symbol', '1')
256 (group
256 (group
257 (or
257 (or
258 ('symbol', '2')
258 ('symbol', '2')
259 ('symbol', '3'))))
259 ('symbol', '3'))))
260 * set:
260 * set:
261 <addset
261 <addset
262 <baseset [1]>,
262 <baseset [1]>,
263 <addset
263 <addset
264 <baseset [2]>,
264 <baseset [2]>,
265 <baseset [3]>>>
265 <baseset [3]>>>
266 1
266 1
267 2
267 2
268 3
268 3
269 $ log '1.0' # tag
269 $ log '1.0' # tag
270 6
270 6
271 $ log 'a' # branch
271 $ log 'a' # branch
272 0
272 0
273 $ log '2785f51ee'
273 $ log '2785f51ee'
274 0
274 0
275 $ log 'date(2005)'
275 $ log 'date(2005)'
276 4
276 4
277 $ log 'date(this is a test)'
277 $ log 'date(this is a test)'
278 hg: parse error at 10: unexpected token: symbol
278 hg: parse error at 10: unexpected token: symbol
279 [255]
279 [255]
280 $ log 'date()'
280 $ log 'date()'
281 hg: parse error: date requires a string
281 hg: parse error: date requires a string
282 [255]
282 [255]
283 $ log 'date'
283 $ log 'date'
284 hg: parse error: can't use date here
284 hg: parse error: can't use date here
285 [255]
285 [255]
286 $ log 'date('
286 $ log 'date('
287 hg: parse error at 5: not a prefix: end
287 hg: parse error at 5: not a prefix: end
288 [255]
288 [255]
289 $ log 'date(tip)'
289 $ log 'date(tip)'
290 abort: invalid date: 'tip'
290 abort: invalid date: 'tip'
291 [255]
291 [255]
292 $ log '"date"'
292 $ log '"date"'
293 abort: unknown revision 'date'!
293 abort: unknown revision 'date'!
294 [255]
294 [255]
295 $ log 'date(2005) and 1::'
295 $ log 'date(2005) and 1::'
296 4
296 4
297
297
298 ancestor can accept 0 or more arguments
298 ancestor can accept 0 or more arguments
299
299
300 $ log 'ancestor()'
300 $ log 'ancestor()'
301 $ log 'ancestor(1)'
301 $ log 'ancestor(1)'
302 1
302 1
303 $ log 'ancestor(4,5)'
303 $ log 'ancestor(4,5)'
304 1
304 1
305 $ log 'ancestor(4,5) and 4'
305 $ log 'ancestor(4,5) and 4'
306 $ log 'ancestor(0,0,1,3)'
306 $ log 'ancestor(0,0,1,3)'
307 0
307 0
308 $ log 'ancestor(3,1,5,3,5,1)'
308 $ log 'ancestor(3,1,5,3,5,1)'
309 1
309 1
310 $ log 'ancestor(0,1,3,5)'
310 $ log 'ancestor(0,1,3,5)'
311 0
311 0
312 $ log 'ancestor(1,2,3,4,5)'
312 $ log 'ancestor(1,2,3,4,5)'
313 1
313 1
314 $ log 'ancestors(5)'
314 $ log 'ancestors(5)'
315 0
315 0
316 1
316 1
317 3
317 3
318 5
318 5
319 $ log 'ancestor(ancestors(5))'
319 $ log 'ancestor(ancestors(5))'
320 0
320 0
321 $ log 'author(bob)'
321 $ log 'author(bob)'
322 2
322 2
323 $ log 'author("re:bob|test")'
323 $ log 'author("re:bob|test")'
324 0
324 0
325 1
325 1
326 2
326 2
327 3
327 3
328 4
328 4
329 5
329 5
330 6
330 6
331 7
331 7
332 8
332 8
333 9
333 9
334 $ log 'branch(Γ©)'
334 $ log 'branch(Γ©)'
335 8
335 8
336 9
336 9
337 $ log 'branch(a)'
337 $ log 'branch(a)'
338 0
338 0
339 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
339 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
340 0 a
340 0 a
341 2 a-b-c-
341 2 a-b-c-
342 3 +a+b+c+
342 3 +a+b+c+
343 4 -a-b-c-
343 4 -a-b-c-
344 5 !a/b/c/
344 5 !a/b/c/
345 6 _a_b_c_
345 6 _a_b_c_
346 7 .a.b.c.
346 7 .a.b.c.
347 $ log 'children(ancestor(4,5))'
347 $ log 'children(ancestor(4,5))'
348 2
348 2
349 3
349 3
350 $ log 'closed()'
350 $ log 'closed()'
351 $ log 'contains(a)'
351 $ log 'contains(a)'
352 0
352 0
353 1
353 1
354 3
354 3
355 5
355 5
356 $ log 'contains("../repo/a")'
356 $ log 'contains("../repo/a")'
357 0
357 0
358 1
358 1
359 3
359 3
360 5
360 5
361 $ log 'desc(B)'
361 $ log 'desc(B)'
362 5
362 5
363 $ log 'descendants(2 or 3)'
363 $ log 'descendants(2 or 3)'
364 2
364 2
365 3
365 3
366 4
366 4
367 5
367 5
368 6
368 6
369 7
369 7
370 8
370 8
371 9
371 9
372 $ log 'file("b*")'
372 $ log 'file("b*")'
373 1
373 1
374 4
374 4
375 $ log 'filelog("b")'
375 $ log 'filelog("b")'
376 1
376 1
377 4
377 4
378 $ log 'filelog("../repo/b")'
378 $ log 'filelog("../repo/b")'
379 1
379 1
380 4
380 4
381 $ log 'follow()'
381 $ log 'follow()'
382 0
382 0
383 1
383 1
384 2
384 2
385 4
385 4
386 8
386 8
387 9
387 9
388 $ log 'grep("issue\d+")'
388 $ log 'grep("issue\d+")'
389 6
389 6
390 $ try 'grep("(")' # invalid regular expression
390 $ try 'grep("(")' # invalid regular expression
391 (func
391 (func
392 ('symbol', 'grep')
392 ('symbol', 'grep')
393 ('string', '('))
393 ('string', '('))
394 hg: parse error: invalid match pattern: unbalanced parenthesis
394 hg: parse error: invalid match pattern: unbalanced parenthesis
395 [255]
395 [255]
396 $ try 'grep("\bissue\d+")'
396 $ try 'grep("\bissue\d+")'
397 (func
397 (func
398 ('symbol', 'grep')
398 ('symbol', 'grep')
399 ('string', '\x08issue\\d+'))
399 ('string', '\x08issue\\d+'))
400 * set:
400 * set:
401 <filteredset
401 <filteredset
402 <fullreposet+ 0:9>>
402 <fullreposet+ 0:9>>
403 $ try 'grep(r"\bissue\d+")'
403 $ try 'grep(r"\bissue\d+")'
404 (func
404 (func
405 ('symbol', 'grep')
405 ('symbol', 'grep')
406 ('string', '\\bissue\\d+'))
406 ('string', '\\bissue\\d+'))
407 * set:
407 * set:
408 <filteredset
408 <filteredset
409 <fullreposet+ 0:9>>
409 <fullreposet+ 0:9>>
410 6
410 6
411 $ try 'grep(r"\")'
411 $ try 'grep(r"\")'
412 hg: parse error at 7: unterminated string
412 hg: parse error at 7: unterminated string
413 [255]
413 [255]
414 $ log 'head()'
414 $ log 'head()'
415 0
415 0
416 1
416 1
417 2
417 2
418 3
418 3
419 4
419 4
420 5
420 5
421 6
421 6
422 7
422 7
423 9
423 9
424 $ log 'heads(6::)'
424 $ log 'heads(6::)'
425 7
425 7
426 $ log 'keyword(issue)'
426 $ log 'keyword(issue)'
427 6
427 6
428 $ log 'keyword("test a")'
428 $ log 'keyword("test a")'
429 $ log 'limit(head(), 1)'
429 $ log 'limit(head(), 1)'
430 0
430 0
431 $ log 'matching(6)'
431 $ log 'matching(6)'
432 6
432 6
433 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
433 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
434 6
434 6
435 7
435 7
436
436
437 Testing min and max
437 Testing min and max
438
438
439 max: simple
439 max: simple
440
440
441 $ log 'max(contains(a))'
441 $ log 'max(contains(a))'
442 5
442 5
443
443
444 max: simple on unordered set)
444 max: simple on unordered set)
445
445
446 $ log 'max((4+0+2+5+7) and contains(a))'
446 $ log 'max((4+0+2+5+7) and contains(a))'
447 5
447 5
448
448
449 max: no result
449 max: no result
450
450
451 $ log 'max(contains(stringthatdoesnotappearanywhere))'
451 $ log 'max(contains(stringthatdoesnotappearanywhere))'
452
452
453 max: no result on unordered set
453 max: no result on unordered set
454
454
455 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
455 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
456
456
457 min: simple
457 min: simple
458
458
459 $ log 'min(contains(a))'
459 $ log 'min(contains(a))'
460 0
460 0
461
461
462 min: simple on unordered set
462 min: simple on unordered set
463
463
464 $ log 'min((4+0+2+5+7) and contains(a))'
464 $ log 'min((4+0+2+5+7) and contains(a))'
465 0
465 0
466
466
467 min: empty
467 min: empty
468
468
469 $ log 'min(contains(stringthatdoesnotappearanywhere))'
469 $ log 'min(contains(stringthatdoesnotappearanywhere))'
470
470
471 min: empty on unordered set
471 min: empty on unordered set
472
472
473 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
473 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
474
474
475
475
476 $ log 'merge()'
476 $ log 'merge()'
477 6
477 6
478 $ log 'branchpoint()'
478 $ log 'branchpoint()'
479 1
479 1
480 4
480 4
481 $ log 'modifies(b)'
481 $ log 'modifies(b)'
482 4
482 4
483 $ log 'modifies("path:b")'
483 $ log 'modifies("path:b")'
484 4
484 4
485 $ log 'modifies("*")'
485 $ log 'modifies("*")'
486 4
486 4
487 6
487 6
488 $ log 'modifies("set:modified()")'
488 $ log 'modifies("set:modified()")'
489 4
489 4
490 $ log 'id(5)'
490 $ log 'id(5)'
491 2
491 2
492 $ log 'only(9)'
492 $ log 'only(9)'
493 8
493 8
494 9
494 9
495 $ log 'only(8)'
495 $ log 'only(8)'
496 8
496 8
497 $ log 'only(9, 5)'
497 $ log 'only(9, 5)'
498 2
498 2
499 4
499 4
500 8
500 8
501 9
501 9
502 $ log 'only(7 + 9, 5 + 2)'
502 $ log 'only(7 + 9, 5 + 2)'
503 4
503 4
504 6
504 6
505 7
505 7
506 8
506 8
507 9
507 9
508
508
509 Test empty set input
509 Test empty set input
510 $ log 'only(p2())'
510 $ log 'only(p2())'
511 $ log 'only(p1(), p2())'
511 $ log 'only(p1(), p2())'
512 0
512 0
513 1
513 1
514 2
514 2
515 4
515 4
516 8
516 8
517 9
517 9
518
518
519 Test '%' operator
519 Test '%' operator
520
520
521 $ log '9%'
521 $ log '9%'
522 8
522 8
523 9
523 9
524 $ log '9%5'
524 $ log '9%5'
525 2
525 2
526 4
526 4
527 8
527 8
528 9
528 9
529 $ log '(7 + 9)%(5 + 2)'
529 $ log '(7 + 9)%(5 + 2)'
530 4
530 4
531 6
531 6
532 7
532 7
533 8
533 8
534 9
534 9
535
535
536 Test opreand of '%' is optimized recursively (issue4670)
536 Test opreand of '%' is optimized recursively (issue4670)
537
537
538 $ try --optimize '8:9-8%'
538 $ try --optimize '8:9-8%'
539 (onlypost
539 (onlypost
540 (minus
540 (minus
541 (range
541 (range
542 ('symbol', '8')
542 ('symbol', '8')
543 ('symbol', '9'))
543 ('symbol', '9'))
544 ('symbol', '8')))
544 ('symbol', '8')))
545 * optimized:
545 * optimized:
546 (func
546 (func
547 ('symbol', 'only')
547 ('symbol', 'only')
548 (and
548 (and
549 (range
549 (range
550 ('symbol', '8')
550 ('symbol', '8')
551 ('symbol', '9'))
551 ('symbol', '9'))
552 (not
552 (not
553 ('symbol', '8'))))
553 ('symbol', '8'))))
554 * set:
554 * set:
555 <baseset+ [8, 9]>
555 <baseset+ [8, 9]>
556 8
556 8
557 9
557 9
558
558
559 Test the order of operations
559 Test the order of operations
560
560
561 $ log '7 + 9%5 + 2'
561 $ log '7 + 9%5 + 2'
562 7
562 7
563 2
563 2
564 4
564 4
565 8
565 8
566 9
566 9
567
567
568 Test explicit numeric revision
568 Test explicit numeric revision
569 $ log 'rev(-2)'
569 $ log 'rev(-2)'
570 $ log 'rev(-1)'
570 $ log 'rev(-1)'
571 -1
571 -1
572 $ log 'rev(0)'
572 $ log 'rev(0)'
573 0
573 0
574 $ log 'rev(9)'
574 $ log 'rev(9)'
575 9
575 9
576 $ log 'rev(10)'
576 $ log 'rev(10)'
577 $ log 'rev(tip)'
577 $ log 'rev(tip)'
578 hg: parse error: rev expects a number
578 hg: parse error: rev expects a number
579 [255]
579 [255]
580
580
581 Test hexadecimal revision
581 Test hexadecimal revision
582 $ log 'id(2)'
582 $ log 'id(2)'
583 abort: 00changelog.i@2: ambiguous identifier!
583 abort: 00changelog.i@2: ambiguous identifier!
584 [255]
584 [255]
585 $ log 'id(23268)'
585 $ log 'id(23268)'
586 4
586 4
587 $ log 'id(2785f51eece)'
587 $ log 'id(2785f51eece)'
588 0
588 0
589 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
589 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
590 8
590 8
591 $ log 'id(d5d0dcbdc4a)'
591 $ log 'id(d5d0dcbdc4a)'
592 $ log 'id(d5d0dcbdc4w)'
592 $ log 'id(d5d0dcbdc4w)'
593 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
593 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
594 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
594 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
595 $ log 'id(1.0)'
595 $ log 'id(1.0)'
596 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
596 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
597
597
598 Test null revision
598 Test null revision
599 $ log '(null)'
599 $ log '(null)'
600 -1
600 -1
601 $ log '(null:0)'
601 $ log '(null:0)'
602 -1
602 -1
603 0
603 0
604 $ log '(0:null)'
604 $ log '(0:null)'
605 0
605 0
606 -1
606 -1
607 $ log 'null::0'
607 $ log 'null::0'
608 -1
608 -1
609 0
609 0
610 $ log 'null:tip - 0:'
610 $ log 'null:tip - 0:'
611 -1
611 -1
612 $ log 'null: and null::' | head -1
612 $ log 'null: and null::' | head -1
613 -1
613 -1
614 $ log 'null: or 0:' | head -2
614 $ log 'null: or 0:' | head -2
615 -1
615 -1
616 0
616 0
617 $ log 'ancestors(null)'
617 $ log 'ancestors(null)'
618 -1
618 -1
619 $ log 'reverse(null:)' | tail -2
619 $ log 'reverse(null:)' | tail -2
620 0
620 0
621 -1
621 -1
622 BROKEN: should be '-1'
622 BROKEN: should be '-1'
623 $ log 'first(null:)'
623 $ log 'first(null:)'
624 BROKEN: should be '-1'
624 BROKEN: should be '-1'
625 $ log 'min(null:)'
625 $ log 'min(null:)'
626 $ log 'tip:null and all()' | tail -2
626 $ log 'tip:null and all()' | tail -2
627 1
627 1
628 0
628 0
629
629
630 Test working-directory revision
630 Test working-directory revision
631 $ hg debugrevspec 'wdir()'
631 $ hg debugrevspec 'wdir()'
632 None
632 None
633 BROKEN: should include 'None'
633 BROKEN: should include 'None'
634 $ hg debugrevspec 'tip or wdir()'
634 $ hg debugrevspec 'tip or wdir()'
635 9
635 9
636 $ hg debugrevspec '0:tip and wdir()'
636 $ hg debugrevspec '0:tip and wdir()'
637
637
638 $ log 'outgoing()'
638 $ log 'outgoing()'
639 8
639 8
640 9
640 9
641 $ log 'outgoing("../remote1")'
641 $ log 'outgoing("../remote1")'
642 8
642 8
643 9
643 9
644 $ log 'outgoing("../remote2")'
644 $ log 'outgoing("../remote2")'
645 3
645 3
646 5
646 5
647 6
647 6
648 7
648 7
649 9
649 9
650 $ log 'p1(merge())'
650 $ log 'p1(merge())'
651 5
651 5
652 $ log 'p2(merge())'
652 $ log 'p2(merge())'
653 4
653 4
654 $ log 'parents(merge())'
654 $ log 'parents(merge())'
655 4
655 4
656 5
656 5
657 $ log 'p1(branchpoint())'
657 $ log 'p1(branchpoint())'
658 0
658 0
659 2
659 2
660 $ log 'p2(branchpoint())'
660 $ log 'p2(branchpoint())'
661 $ log 'parents(branchpoint())'
661 $ log 'parents(branchpoint())'
662 0
662 0
663 2
663 2
664 $ log 'removes(a)'
664 $ log 'removes(a)'
665 2
665 2
666 6
666 6
667 $ log 'roots(all())'
667 $ log 'roots(all())'
668 0
668 0
669 $ log 'reverse(2 or 3 or 4 or 5)'
669 $ log 'reverse(2 or 3 or 4 or 5)'
670 5
670 5
671 4
671 4
672 3
672 3
673 2
673 2
674 $ log 'reverse(all())'
674 $ log 'reverse(all())'
675 9
675 9
676 8
676 8
677 7
677 7
678 6
678 6
679 5
679 5
680 4
680 4
681 3
681 3
682 2
682 2
683 1
683 1
684 0
684 0
685 $ log 'reverse(all()) & filelog(b)'
685 $ log 'reverse(all()) & filelog(b)'
686 4
686 4
687 1
687 1
688 $ log 'rev(5)'
688 $ log 'rev(5)'
689 5
689 5
690 $ log 'sort(limit(reverse(all()), 3))'
690 $ log 'sort(limit(reverse(all()), 3))'
691 7
691 7
692 8
692 8
693 9
693 9
694 $ log 'sort(2 or 3 or 4 or 5, date)'
694 $ log 'sort(2 or 3 or 4 or 5, date)'
695 2
695 2
696 3
696 3
697 5
697 5
698 4
698 4
699 $ log 'tagged()'
699 $ log 'tagged()'
700 6
700 6
701 $ log 'tag()'
701 $ log 'tag()'
702 6
702 6
703 $ log 'tag(1.0)'
703 $ log 'tag(1.0)'
704 6
704 6
705 $ log 'tag(tip)'
705 $ log 'tag(tip)'
706 9
706 9
707
707
708 test sort revset
708 test sort revset
709 --------------------------------------------
709 --------------------------------------------
710
710
711 test when adding two unordered revsets
711 test when adding two unordered revsets
712
712
713 $ log 'sort(keyword(issue) or modifies(b))'
713 $ log 'sort(keyword(issue) or modifies(b))'
714 4
714 4
715 6
715 6
716
716
717 test when sorting a reversed collection in the same way it is
717 test when sorting a reversed collection in the same way it is
718
718
719 $ log 'sort(reverse(all()), -rev)'
719 $ log 'sort(reverse(all()), -rev)'
720 9
720 9
721 8
721 8
722 7
722 7
723 6
723 6
724 5
724 5
725 4
725 4
726 3
726 3
727 2
727 2
728 1
728 1
729 0
729 0
730
730
731 test when sorting a reversed collection
731 test when sorting a reversed collection
732
732
733 $ log 'sort(reverse(all()), rev)'
733 $ log 'sort(reverse(all()), rev)'
734 0
734 0
735 1
735 1
736 2
736 2
737 3
737 3
738 4
738 4
739 5
739 5
740 6
740 6
741 7
741 7
742 8
742 8
743 9
743 9
744
744
745
745
746 test sorting two sorted collections in different orders
746 test sorting two sorted collections in different orders
747
747
748 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
748 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
749 2
749 2
750 6
750 6
751 8
751 8
752 9
752 9
753
753
754 test sorting two sorted collections in different orders backwards
754 test sorting two sorted collections in different orders backwards
755
755
756 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
756 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
757 9
757 9
758 8
758 8
759 6
759 6
760 2
760 2
761
761
762 test subtracting something from an addset
762 test subtracting something from an addset
763
763
764 $ log '(outgoing() or removes(a)) - removes(a)'
764 $ log '(outgoing() or removes(a)) - removes(a)'
765 8
765 8
766 9
766 9
767
767
768 test intersecting something with an addset
768 test intersecting something with an addset
769
769
770 $ log 'parents(outgoing() or removes(a))'
770 $ log 'parents(outgoing() or removes(a))'
771 1
771 1
772 4
772 4
773 5
773 5
774 8
774 8
775
775
776 test that `or` operation combines elements in the right order:
776 test that `or` operation combines elements in the right order:
777
777
778 $ log '3:4 or 2:5'
778 $ log '3:4 or 2:5'
779 3
779 3
780 4
780 4
781 2
781 2
782 5
782 5
783 $ log '3:4 or 5:2'
783 $ log '3:4 or 5:2'
784 3
784 3
785 4
785 4
786 5
786 5
787 2
787 2
788 $ log 'sort(3:4 or 2:5)'
788 $ log 'sort(3:4 or 2:5)'
789 2
789 2
790 3
790 3
791 4
791 4
792 5
792 5
793 $ log 'sort(3:4 or 5:2)'
793 $ log 'sort(3:4 or 5:2)'
794 2
794 2
795 3
795 3
796 4
796 4
797 5
797 5
798
798
799 check that conversion to only works
799 check that conversion to only works
800 $ try --optimize '::3 - ::1'
800 $ try --optimize '::3 - ::1'
801 (minus
801 (minus
802 (dagrangepre
802 (dagrangepre
803 ('symbol', '3'))
803 ('symbol', '3'))
804 (dagrangepre
804 (dagrangepre
805 ('symbol', '1')))
805 ('symbol', '1')))
806 * optimized:
806 * optimized:
807 (func
807 (func
808 ('symbol', 'only')
808 ('symbol', 'only')
809 (list
809 (list
810 ('symbol', '3')
810 ('symbol', '3')
811 ('symbol', '1')))
811 ('symbol', '1')))
812 * set:
812 * set:
813 <baseset+ [3]>
813 <baseset+ [3]>
814 3
814 3
815 $ try --optimize 'ancestors(1) - ancestors(3)'
815 $ try --optimize 'ancestors(1) - ancestors(3)'
816 (minus
816 (minus
817 (func
817 (func
818 ('symbol', 'ancestors')
818 ('symbol', 'ancestors')
819 ('symbol', '1'))
819 ('symbol', '1'))
820 (func
820 (func
821 ('symbol', 'ancestors')
821 ('symbol', 'ancestors')
822 ('symbol', '3')))
822 ('symbol', '3')))
823 * optimized:
823 * optimized:
824 (func
824 (func
825 ('symbol', 'only')
825 ('symbol', 'only')
826 (list
826 (list
827 ('symbol', '1')
827 ('symbol', '1')
828 ('symbol', '3')))
828 ('symbol', '3')))
829 * set:
829 * set:
830 <baseset+ []>
830 <baseset+ []>
831 $ try --optimize 'not ::2 and ::6'
831 $ try --optimize 'not ::2 and ::6'
832 (and
832 (and
833 (not
833 (not
834 (dagrangepre
834 (dagrangepre
835 ('symbol', '2')))
835 ('symbol', '2')))
836 (dagrangepre
836 (dagrangepre
837 ('symbol', '6')))
837 ('symbol', '6')))
838 * optimized:
838 * optimized:
839 (func
839 (func
840 ('symbol', 'only')
840 ('symbol', 'only')
841 (list
841 (list
842 ('symbol', '6')
842 ('symbol', '6')
843 ('symbol', '2')))
843 ('symbol', '2')))
844 * set:
844 * set:
845 <baseset+ [3, 4, 5, 6]>
845 <baseset+ [3, 4, 5, 6]>
846 3
846 3
847 4
847 4
848 5
848 5
849 6
849 6
850 $ try --optimize 'ancestors(6) and not ancestors(4)'
850 $ try --optimize 'ancestors(6) and not ancestors(4)'
851 (and
851 (and
852 (func
852 (func
853 ('symbol', 'ancestors')
853 ('symbol', 'ancestors')
854 ('symbol', '6'))
854 ('symbol', '6'))
855 (not
855 (not
856 (func
856 (func
857 ('symbol', 'ancestors')
857 ('symbol', 'ancestors')
858 ('symbol', '4'))))
858 ('symbol', '4'))))
859 * optimized:
859 * optimized:
860 (func
860 (func
861 ('symbol', 'only')
861 ('symbol', 'only')
862 (list
862 (list
863 ('symbol', '6')
863 ('symbol', '6')
864 ('symbol', '4')))
864 ('symbol', '4')))
865 * set:
865 * set:
866 <baseset+ [3, 5, 6]>
866 <baseset+ [3, 5, 6]>
867 3
867 3
868 5
868 5
869 6
869 6
870
870
871 we can use patterns when searching for tags
871 we can use patterns when searching for tags
872
872
873 $ log 'tag("1..*")'
873 $ log 'tag("1..*")'
874 abort: tag '1..*' does not exist!
874 abort: tag '1..*' does not exist!
875 [255]
875 [255]
876 $ log 'tag("re:1..*")'
876 $ log 'tag("re:1..*")'
877 6
877 6
878 $ log 'tag("re:[0-9].[0-9]")'
878 $ log 'tag("re:[0-9].[0-9]")'
879 6
879 6
880 $ log 'tag("literal:1.0")'
880 $ log 'tag("literal:1.0")'
881 6
881 6
882 $ log 'tag("re:0..*")'
882 $ log 'tag("re:0..*")'
883
883
884 $ log 'tag(unknown)'
884 $ log 'tag(unknown)'
885 abort: tag 'unknown' does not exist!
885 abort: tag 'unknown' does not exist!
886 [255]
886 [255]
887 $ log 'tag("re:unknown")'
887 $ log 'tag("re:unknown")'
888 $ log 'present(tag("unknown"))'
888 $ log 'present(tag("unknown"))'
889 $ log 'present(tag("re:unknown"))'
889 $ log 'present(tag("re:unknown"))'
890 $ log 'branch(unknown)'
890 $ log 'branch(unknown)'
891 abort: unknown revision 'unknown'!
891 abort: unknown revision 'unknown'!
892 [255]
892 [255]
893 $ log 'branch("re:unknown")'
893 $ log 'branch("re:unknown")'
894 $ log 'present(branch("unknown"))'
894 $ log 'present(branch("unknown"))'
895 $ log 'present(branch("re:unknown"))'
895 $ log 'present(branch("re:unknown"))'
896 $ log 'user(bob)'
896 $ log 'user(bob)'
897 2
897 2
898
898
899 $ log '4::8'
899 $ log '4::8'
900 4
900 4
901 8
901 8
902 $ log '4:8'
902 $ log '4:8'
903 4
903 4
904 5
904 5
905 6
905 6
906 7
906 7
907 8
907 8
908
908
909 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
909 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
910 4
910 4
911 2
911 2
912 5
912 5
913
913
914 $ log 'not 0 and 0:2'
914 $ log 'not 0 and 0:2'
915 1
915 1
916 2
916 2
917 $ log 'not 1 and 0:2'
917 $ log 'not 1 and 0:2'
918 0
918 0
919 2
919 2
920 $ log 'not 2 and 0:2'
920 $ log 'not 2 and 0:2'
921 0
921 0
922 1
922 1
923 $ log '(1 and 2)::'
923 $ log '(1 and 2)::'
924 $ log '(1 and 2):'
924 $ log '(1 and 2):'
925 $ log '(1 and 2):3'
925 $ log '(1 and 2):3'
926 $ log 'sort(head(), -rev)'
926 $ log 'sort(head(), -rev)'
927 9
927 9
928 7
928 7
929 6
929 6
930 5
930 5
931 4
931 4
932 3
932 3
933 2
933 2
934 1
934 1
935 0
935 0
936 $ log '4::8 - 8'
936 $ log '4::8 - 8'
937 4
937 4
938 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
938 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
939 2
939 2
940 3
940 3
941 1
941 1
942
942
943 $ log 'named("unknown")'
943 $ log 'named("unknown")'
944 abort: namespace 'unknown' does not exist!
944 abort: namespace 'unknown' does not exist!
945 [255]
945 [255]
946 $ log 'named("re:unknown")'
946 $ log 'named("re:unknown")'
947 abort: no namespace exists that match 'unknown'!
947 abort: no namespace exists that match 'unknown'!
948 [255]
948 [255]
949 $ log 'present(named("unknown"))'
949 $ log 'present(named("unknown"))'
950 $ log 'present(named("re:unknown"))'
950 $ log 'present(named("re:unknown"))'
951
951
952 $ log 'tag()'
952 $ log 'tag()'
953 6
953 6
954 $ log 'named("tags")'
954 $ log 'named("tags")'
955 6
955 6
956
956
957 issue2437
957 issue2437
958
958
959 $ log '3 and p1(5)'
959 $ log '3 and p1(5)'
960 3
960 3
961 $ log '4 and p2(6)'
961 $ log '4 and p2(6)'
962 4
962 4
963 $ log '1 and parents(:2)'
963 $ log '1 and parents(:2)'
964 1
964 1
965 $ log '2 and children(1:)'
965 $ log '2 and children(1:)'
966 2
966 2
967 $ log 'roots(all()) or roots(all())'
967 $ log 'roots(all()) or roots(all())'
968 0
968 0
969 $ hg debugrevspec 'roots(all()) or roots(all())'
969 $ hg debugrevspec 'roots(all()) or roots(all())'
970 0
970 0
971 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
971 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
972 9
972 9
973 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
973 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
974 4
974 4
975
975
976 issue2654: report a parse error if the revset was not completely parsed
976 issue2654: report a parse error if the revset was not completely parsed
977
977
978 $ log '1 OR 2'
978 $ log '1 OR 2'
979 hg: parse error at 2: invalid token
979 hg: parse error at 2: invalid token
980 [255]
980 [255]
981
981
982 or operator should preserve ordering:
982 or operator should preserve ordering:
983 $ log 'reverse(2::4) or tip'
983 $ log 'reverse(2::4) or tip'
984 4
984 4
985 2
985 2
986 9
986 9
987
987
988 parentrevspec
988 parentrevspec
989
989
990 $ log 'merge()^0'
990 $ log 'merge()^0'
991 6
991 6
992 $ log 'merge()^'
992 $ log 'merge()^'
993 5
993 5
994 $ log 'merge()^1'
994 $ log 'merge()^1'
995 5
995 5
996 $ log 'merge()^2'
996 $ log 'merge()^2'
997 4
997 4
998 $ log 'merge()^^'
998 $ log 'merge()^^'
999 3
999 3
1000 $ log 'merge()^1^'
1000 $ log 'merge()^1^'
1001 3
1001 3
1002 $ log 'merge()^^^'
1002 $ log 'merge()^^^'
1003 1
1003 1
1004
1004
1005 $ log 'merge()~0'
1005 $ log 'merge()~0'
1006 6
1006 6
1007 $ log 'merge()~1'
1007 $ log 'merge()~1'
1008 5
1008 5
1009 $ log 'merge()~2'
1009 $ log 'merge()~2'
1010 3
1010 3
1011 $ log 'merge()~2^1'
1011 $ log 'merge()~2^1'
1012 1
1012 1
1013 $ log 'merge()~3'
1013 $ log 'merge()~3'
1014 1
1014 1
1015
1015
1016 $ log '(-3:tip)^'
1016 $ log '(-3:tip)^'
1017 4
1017 4
1018 6
1018 6
1019 8
1019 8
1020
1020
1021 $ log 'tip^foo'
1021 $ log 'tip^foo'
1022 hg: parse error: ^ expects a number 0, 1, or 2
1022 hg: parse error: ^ expects a number 0, 1, or 2
1023 [255]
1023 [255]
1024
1024
1025 Bogus function gets suggestions
1025 Bogus function gets suggestions
1026 $ log 'add()'
1026 $ log 'add()'
1027 hg: parse error: unknown identifier: add
1027 hg: parse error: unknown identifier: add
1028 (did you mean 'adds'?)
1028 (did you mean 'adds'?)
1029 [255]
1029 [255]
1030 $ log 'added()'
1030 $ log 'added()'
1031 hg: parse error: unknown identifier: added
1031 hg: parse error: unknown identifier: added
1032 (did you mean 'adds'?)
1032 (did you mean 'adds'?)
1033 [255]
1033 [255]
1034 $ log 'remo()'
1034 $ log 'remo()'
1035 hg: parse error: unknown identifier: remo
1035 hg: parse error: unknown identifier: remo
1036 (did you mean one of remote, removes?)
1036 (did you mean one of remote, removes?)
1037 [255]
1037 [255]
1038 $ log 'babar()'
1038 $ log 'babar()'
1039 hg: parse error: unknown identifier: babar
1039 hg: parse error: unknown identifier: babar
1040 [255]
1040 [255]
1041
1041
1042 multiple revspecs
1042 multiple revspecs
1043
1043
1044 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1044 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1045 8
1045 8
1046 9
1046 9
1047 4
1047 4
1048 5
1048 5
1049 6
1049 6
1050 7
1050 7
1051
1051
1052 test usage in revpair (with "+")
1052 test usage in revpair (with "+")
1053
1053
1054 (real pair)
1054 (real pair)
1055
1055
1056 $ hg diff -r 'tip^^' -r 'tip'
1056 $ hg diff -r 'tip^^' -r 'tip'
1057 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1057 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1058 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1059 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1059 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1060 @@ -0,0 +1,1 @@
1060 @@ -0,0 +1,1 @@
1061 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1061 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1062 $ hg diff -r 'tip^^::tip'
1062 $ hg diff -r 'tip^^::tip'
1063 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1063 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1064 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1064 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1065 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1065 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1066 @@ -0,0 +1,1 @@
1066 @@ -0,0 +1,1 @@
1067 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1067 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1068
1068
1069 (single rev)
1069 (single rev)
1070
1070
1071 $ hg diff -r 'tip^' -r 'tip^'
1071 $ hg diff -r 'tip^' -r 'tip^'
1072 $ hg diff -r 'tip^::tip^ or tip^'
1072 $ hg diff -r 'tip^::tip^ or tip^'
1073
1073
1074 (single rev that does not looks like a range)
1074 (single rev that does not looks like a range)
1075
1075
1076 $ hg diff -r 'tip^ or tip^'
1076 $ hg diff -r 'tip^ or tip^'
1077 diff -r d5d0dcbdc4d9 .hgtags
1077 diff -r d5d0dcbdc4d9 .hgtags
1078 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1078 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1079 +++ b/.hgtags * (glob)
1079 +++ b/.hgtags * (glob)
1080 @@ -0,0 +1,1 @@
1080 @@ -0,0 +1,1 @@
1081 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1081 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1082
1082
1083 (no rev)
1083 (no rev)
1084
1084
1085 $ hg diff -r 'author("babar") or author("celeste")'
1085 $ hg diff -r 'author("babar") or author("celeste")'
1086 abort: empty revision range
1086 abort: empty revision range
1087 [255]
1087 [255]
1088
1088
1089 aliases:
1089 aliases:
1090
1090
1091 $ echo '[revsetalias]' >> .hg/hgrc
1091 $ echo '[revsetalias]' >> .hg/hgrc
1092 $ echo 'm = merge()' >> .hg/hgrc
1092 $ echo 'm = merge()' >> .hg/hgrc
1093 (revset aliases can override builtin revsets)
1093 (revset aliases can override builtin revsets)
1094 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1094 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1095 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1095 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1096 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1096 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1097 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1097 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1098 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1098 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1099
1099
1100 $ try m
1100 $ try m
1101 ('symbol', 'm')
1101 ('symbol', 'm')
1102 (func
1102 (func
1103 ('symbol', 'merge')
1103 ('symbol', 'merge')
1104 None)
1104 None)
1105 * set:
1105 * set:
1106 <filteredset
1106 <filteredset
1107 <fullreposet+ 0:9>>
1107 <fullreposet+ 0:9>>
1108 6
1108 6
1109
1109
1110 $ HGPLAIN=1
1110 $ HGPLAIN=1
1111 $ export HGPLAIN
1111 $ export HGPLAIN
1112 $ try m
1112 $ try m
1113 ('symbol', 'm')
1113 ('symbol', 'm')
1114 abort: unknown revision 'm'!
1114 abort: unknown revision 'm'!
1115 [255]
1115 [255]
1116
1116
1117 $ HGPLAINEXCEPT=revsetalias
1117 $ HGPLAINEXCEPT=revsetalias
1118 $ export HGPLAINEXCEPT
1118 $ export HGPLAINEXCEPT
1119 $ try m
1119 $ try m
1120 ('symbol', 'm')
1120 ('symbol', 'm')
1121 (func
1121 (func
1122 ('symbol', 'merge')
1122 ('symbol', 'merge')
1123 None)
1123 None)
1124 * set:
1124 * set:
1125 <filteredset
1125 <filteredset
1126 <fullreposet+ 0:9>>
1126 <fullreposet+ 0:9>>
1127 6
1127 6
1128
1128
1129 $ unset HGPLAIN
1129 $ unset HGPLAIN
1130 $ unset HGPLAINEXCEPT
1130 $ unset HGPLAINEXCEPT
1131
1131
1132 $ try 'p2(.)'
1132 $ try 'p2(.)'
1133 (func
1133 (func
1134 ('symbol', 'p2')
1134 ('symbol', 'p2')
1135 ('symbol', '.'))
1135 ('symbol', '.'))
1136 (func
1136 (func
1137 ('symbol', 'p1')
1137 ('symbol', 'p1')
1138 ('symbol', '.'))
1138 ('symbol', '.'))
1139 * set:
1139 * set:
1140 <baseset+ [8]>
1140 <baseset+ [8]>
1141 8
1141 8
1142
1142
1143 $ HGPLAIN=1
1143 $ HGPLAIN=1
1144 $ export HGPLAIN
1144 $ export HGPLAIN
1145 $ try 'p2(.)'
1145 $ try 'p2(.)'
1146 (func
1146 (func
1147 ('symbol', 'p2')
1147 ('symbol', 'p2')
1148 ('symbol', '.'))
1148 ('symbol', '.'))
1149 * set:
1149 * set:
1150 <baseset+ []>
1150 <baseset+ []>
1151
1151
1152 $ HGPLAINEXCEPT=revsetalias
1152 $ HGPLAINEXCEPT=revsetalias
1153 $ export HGPLAINEXCEPT
1153 $ export HGPLAINEXCEPT
1154 $ try 'p2(.)'
1154 $ try 'p2(.)'
1155 (func
1155 (func
1156 ('symbol', 'p2')
1156 ('symbol', 'p2')
1157 ('symbol', '.'))
1157 ('symbol', '.'))
1158 (func
1158 (func
1159 ('symbol', 'p1')
1159 ('symbol', 'p1')
1160 ('symbol', '.'))
1160 ('symbol', '.'))
1161 * set:
1161 * set:
1162 <baseset+ [8]>
1162 <baseset+ [8]>
1163 8
1163 8
1164
1164
1165 $ unset HGPLAIN
1165 $ unset HGPLAIN
1166 $ unset HGPLAINEXCEPT
1166 $ unset HGPLAINEXCEPT
1167
1167
1168 test alias recursion
1168 test alias recursion
1169
1169
1170 $ try sincem
1170 $ try sincem
1171 ('symbol', 'sincem')
1171 ('symbol', 'sincem')
1172 (func
1172 (func
1173 ('symbol', 'descendants')
1173 ('symbol', 'descendants')
1174 (func
1174 (func
1175 ('symbol', 'merge')
1175 ('symbol', 'merge')
1176 None))
1176 None))
1177 * set:
1177 * set:
1178 <addset+
1178 <addset+
1179 <filteredset
1179 <filteredset
1180 <fullreposet+ 0:9>>,
1180 <fullreposet+ 0:9>>,
1181 <generatorset+>>
1181 <generatorset+>>
1182 6
1182 6
1183 7
1183 7
1184
1184
1185 test infinite recursion
1185 test infinite recursion
1186
1186
1187 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1187 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1188 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1188 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1189 $ try recurse1
1189 $ try recurse1
1190 ('symbol', 'recurse1')
1190 ('symbol', 'recurse1')
1191 hg: parse error: infinite expansion of revset alias "recurse1" detected
1191 hg: parse error: infinite expansion of revset alias "recurse1" detected
1192 [255]
1192 [255]
1193
1193
1194 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1194 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1195 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1195 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1196 $ try "level2(level1(1, 2), 3)"
1196 $ try "level2(level1(1, 2), 3)"
1197 (func
1197 (func
1198 ('symbol', 'level2')
1198 ('symbol', 'level2')
1199 (list
1199 (list
1200 (func
1200 (func
1201 ('symbol', 'level1')
1201 ('symbol', 'level1')
1202 (list
1202 (list
1203 ('symbol', '1')
1203 ('symbol', '1')
1204 ('symbol', '2')))
1204 ('symbol', '2')))
1205 ('symbol', '3')))
1205 ('symbol', '3')))
1206 (or
1206 (or
1207 ('symbol', '3')
1207 ('symbol', '3')
1208 (or
1208 (or
1209 ('symbol', '1')
1209 ('symbol', '1')
1210 ('symbol', '2')))
1210 ('symbol', '2')))
1211 * set:
1211 * set:
1212 <addset
1212 <addset
1213 <baseset [3]>,
1213 <baseset [3]>,
1214 <addset
1214 <addset
1215 <baseset [1]>,
1215 <baseset [1]>,
1216 <baseset [2]>>>
1216 <baseset [2]>>>
1217 3
1217 3
1218 1
1218 1
1219 2
1219 2
1220
1220
1221 test nesting and variable passing
1221 test nesting and variable passing
1222
1222
1223 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1223 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1224 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1224 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1225 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1225 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1226 $ try 'nested(2:5)'
1226 $ try 'nested(2:5)'
1227 (func
1227 (func
1228 ('symbol', 'nested')
1228 ('symbol', 'nested')
1229 (range
1229 (range
1230 ('symbol', '2')
1230 ('symbol', '2')
1231 ('symbol', '5')))
1231 ('symbol', '5')))
1232 (func
1232 (func
1233 ('symbol', 'max')
1233 ('symbol', 'max')
1234 (range
1234 (range
1235 ('symbol', '2')
1235 ('symbol', '2')
1236 ('symbol', '5')))
1236 ('symbol', '5')))
1237 * set:
1237 * set:
1238 <baseset [5]>
1238 <baseset [5]>
1239 5
1239 5
1240
1240
1241 test variable isolation, variable placeholders are rewritten as string
1241 test variable isolation, variable placeholders are rewritten as string
1242 then parsed and matched again as string. Check they do not leak too
1242 then parsed and matched again as string. Check they do not leak too
1243 far away.
1243 far away.
1244
1244
1245 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1245 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1246 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1246 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1247 $ try 'callinjection(2:5)'
1247 $ try 'callinjection(2:5)'
1248 (func
1248 (func
1249 ('symbol', 'callinjection')
1249 ('symbol', 'callinjection')
1250 (range
1250 (range
1251 ('symbol', '2')
1251 ('symbol', '2')
1252 ('symbol', '5')))
1252 ('symbol', '5')))
1253 (func
1253 (func
1254 ('symbol', 'descendants')
1254 ('symbol', 'descendants')
1255 (func
1255 (func
1256 ('symbol', 'max')
1256 ('symbol', 'max')
1257 ('string', '$1')))
1257 ('string', '$1')))
1258 abort: unknown revision '$1'!
1258 abort: unknown revision '$1'!
1259 [255]
1259 [255]
1260
1260
1261 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1261 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1262 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1262 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1263 $ try 'callinjection2(2:5)'
1263 $ try 'callinjection2(2:5)'
1264 (func
1264 (func
1265 ('symbol', 'callinjection2')
1265 ('symbol', 'callinjection2')
1266 (range
1266 (range
1267 ('symbol', '2')
1267 ('symbol', '2')
1268 ('symbol', '5')))
1268 ('symbol', '5')))
1269 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1269 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1270 [255]
1270 [255]
1271 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1271 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1272 ('symbol', 'tip')
1272 ('symbol', 'tip')
1273 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1273 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1274 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1274 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1275 * set:
1275 * set:
1276 <baseset [9]>
1276 <baseset [9]>
1277 9
1277 9
1278 >>> data = file('.hg/hgrc', 'rb').read()
1278 >>> data = file('.hg/hgrc', 'rb').read()
1279 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1279 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1280
1280
1281 $ try 'tip'
1281 $ try 'tip'
1282 ('symbol', 'tip')
1282 ('symbol', 'tip')
1283 * set:
1283 * set:
1284 <baseset [9]>
1284 <baseset [9]>
1285 9
1285 9
1286
1286
1287 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1287 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1288 ('symbol', 'tip')
1288 ('symbol', 'tip')
1289 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1289 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1290 * set:
1290 * set:
1291 <baseset [9]>
1291 <baseset [9]>
1292 9
1292 9
1293 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1293 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1294 $ try 'strictreplacing("foo", tip)'
1294 $ try 'strictreplacing("foo", tip)'
1295 (func
1295 (func
1296 ('symbol', 'strictreplacing')
1296 ('symbol', 'strictreplacing')
1297 (list
1297 (list
1298 ('string', 'foo')
1298 ('string', 'foo')
1299 ('symbol', 'tip')))
1299 ('symbol', 'tip')))
1300 (or
1300 (or
1301 ('symbol', 'tip')
1301 ('symbol', 'tip')
1302 (func
1302 (func
1303 ('symbol', 'desc')
1303 ('symbol', 'desc')
1304 ('string', '$1')))
1304 ('string', '$1')))
1305 * set:
1305 * set:
1306 <addset
1306 <addset
1307 <baseset [9]>,
1307 <baseset [9]>,
1308 <filteredset
1308 <filteredset
1309 <filteredset
1309 <filteredset
1310 <fullreposet+ 0:9>>>>
1310 <fullreposet+ 0:9>>>>
1311 9
1311 9
1312
1312
1313 $ try 'd(2:5)'
1313 $ try 'd(2:5)'
1314 (func
1314 (func
1315 ('symbol', 'd')
1315 ('symbol', 'd')
1316 (range
1316 (range
1317 ('symbol', '2')
1317 ('symbol', '2')
1318 ('symbol', '5')))
1318 ('symbol', '5')))
1319 (func
1319 (func
1320 ('symbol', 'reverse')
1320 ('symbol', 'reverse')
1321 (func
1321 (func
1322 ('symbol', 'sort')
1322 ('symbol', 'sort')
1323 (list
1323 (list
1324 (range
1324 (range
1325 ('symbol', '2')
1325 ('symbol', '2')
1326 ('symbol', '5'))
1326 ('symbol', '5'))
1327 ('symbol', 'date'))))
1327 ('symbol', 'date'))))
1328 * set:
1328 * set:
1329 <baseset [4, 5, 3, 2]>
1329 <baseset [4, 5, 3, 2]>
1330 4
1330 4
1331 5
1331 5
1332 3
1332 3
1333 2
1333 2
1334 $ try 'rs(2 or 3, date)'
1334 $ try 'rs(2 or 3, date)'
1335 (func
1335 (func
1336 ('symbol', 'rs')
1336 ('symbol', 'rs')
1337 (list
1337 (list
1338 (or
1338 (or
1339 ('symbol', '2')
1339 ('symbol', '2')
1340 ('symbol', '3'))
1340 ('symbol', '3'))
1341 ('symbol', 'date')))
1341 ('symbol', 'date')))
1342 (func
1342 (func
1343 ('symbol', 'reverse')
1343 ('symbol', 'reverse')
1344 (func
1344 (func
1345 ('symbol', 'sort')
1345 ('symbol', 'sort')
1346 (list
1346 (list
1347 (or
1347 (or
1348 ('symbol', '2')
1348 ('symbol', '2')
1349 ('symbol', '3'))
1349 ('symbol', '3'))
1350 ('symbol', 'date'))))
1350 ('symbol', 'date'))))
1351 * set:
1351 * set:
1352 <baseset [3, 2]>
1352 <baseset [3, 2]>
1353 3
1353 3
1354 2
1354 2
1355 $ try 'rs()'
1355 $ try 'rs()'
1356 (func
1356 (func
1357 ('symbol', 'rs')
1357 ('symbol', 'rs')
1358 None)
1358 None)
1359 hg: parse error: invalid number of arguments: 0
1359 hg: parse error: invalid number of arguments: 0
1360 [255]
1360 [255]
1361 $ try 'rs(2)'
1361 $ try 'rs(2)'
1362 (func
1362 (func
1363 ('symbol', 'rs')
1363 ('symbol', 'rs')
1364 ('symbol', '2'))
1364 ('symbol', '2'))
1365 hg: parse error: invalid number of arguments: 1
1365 hg: parse error: invalid number of arguments: 1
1366 [255]
1366 [255]
1367 $ try 'rs(2, data, 7)'
1367 $ try 'rs(2, data, 7)'
1368 (func
1368 (func
1369 ('symbol', 'rs')
1369 ('symbol', 'rs')
1370 (list
1370 (list
1371 (list
1371 (list
1372 ('symbol', '2')
1372 ('symbol', '2')
1373 ('symbol', 'data'))
1373 ('symbol', 'data'))
1374 ('symbol', '7')))
1374 ('symbol', '7')))
1375 hg: parse error: invalid number of arguments: 3
1375 hg: parse error: invalid number of arguments: 3
1376 [255]
1376 [255]
1377 $ try 'rs4(2 or 3, x, x, date)'
1377 $ try 'rs4(2 or 3, x, x, date)'
1378 (func
1378 (func
1379 ('symbol', 'rs4')
1379 ('symbol', 'rs4')
1380 (list
1380 (list
1381 (list
1381 (list
1382 (list
1382 (list
1383 (or
1383 (or
1384 ('symbol', '2')
1384 ('symbol', '2')
1385 ('symbol', '3'))
1385 ('symbol', '3'))
1386 ('symbol', 'x'))
1386 ('symbol', 'x'))
1387 ('symbol', 'x'))
1387 ('symbol', 'x'))
1388 ('symbol', 'date')))
1388 ('symbol', 'date')))
1389 (func
1389 (func
1390 ('symbol', 'reverse')
1390 ('symbol', 'reverse')
1391 (func
1391 (func
1392 ('symbol', 'sort')
1392 ('symbol', 'sort')
1393 (list
1393 (list
1394 (or
1394 (or
1395 ('symbol', '2')
1395 ('symbol', '2')
1396 ('symbol', '3'))
1396 ('symbol', '3'))
1397 ('symbol', 'date'))))
1397 ('symbol', 'date'))))
1398 * set:
1398 * set:
1399 <baseset [3, 2]>
1399 <baseset [3, 2]>
1400 3
1400 3
1401 2
1401 2
1402
1402
1403 issue4553: check that revset aliases override existing hash prefix
1403 issue4553: check that revset aliases override existing hash prefix
1404
1404
1405 $ hg log -qr e
1405 $ hg log -qr e
1406 6:e0cc66ef77e8
1406 6:e0cc66ef77e8
1407
1407
1408 $ hg log -qr e --config revsetalias.e="all()"
1408 $ hg log -qr e --config revsetalias.e="all()"
1409 0:2785f51eece5
1409 0:2785f51eece5
1410 1:d75937da8da0
1410 1:d75937da8da0
1411 2:5ed5505e9f1c
1411 2:5ed5505e9f1c
1412 3:8528aa5637f2
1412 3:8528aa5637f2
1413 4:2326846efdab
1413 4:2326846efdab
1414 5:904fa392b941
1414 5:904fa392b941
1415 6:e0cc66ef77e8
1415 6:e0cc66ef77e8
1416 7:013af1973af4
1416 7:013af1973af4
1417 8:d5d0dcbdc4d9
1417 8:d5d0dcbdc4d9
1418 9:24286f4ae135
1418 9:24286f4ae135
1419
1419
1420 $ hg log -qr e: --config revsetalias.e="0"
1420 $ hg log -qr e: --config revsetalias.e="0"
1421 0:2785f51eece5
1421 0:2785f51eece5
1422 1:d75937da8da0
1422 1:d75937da8da0
1423 2:5ed5505e9f1c
1423 2:5ed5505e9f1c
1424 3:8528aa5637f2
1424 3:8528aa5637f2
1425 4:2326846efdab
1425 4:2326846efdab
1426 5:904fa392b941
1426 5:904fa392b941
1427 6:e0cc66ef77e8
1427 6:e0cc66ef77e8
1428 7:013af1973af4
1428 7:013af1973af4
1429 8:d5d0dcbdc4d9
1429 8:d5d0dcbdc4d9
1430 9:24286f4ae135
1430 9:24286f4ae135
1431
1431
1432 $ hg log -qr :e --config revsetalias.e="9"
1432 $ hg log -qr :e --config revsetalias.e="9"
1433 0:2785f51eece5
1433 0:2785f51eece5
1434 1:d75937da8da0
1434 1:d75937da8da0
1435 2:5ed5505e9f1c
1435 2:5ed5505e9f1c
1436 3:8528aa5637f2
1436 3:8528aa5637f2
1437 4:2326846efdab
1437 4:2326846efdab
1438 5:904fa392b941
1438 5:904fa392b941
1439 6:e0cc66ef77e8
1439 6:e0cc66ef77e8
1440 7:013af1973af4
1440 7:013af1973af4
1441 8:d5d0dcbdc4d9
1441 8:d5d0dcbdc4d9
1442 9:24286f4ae135
1442 9:24286f4ae135
1443
1443
1444 $ hg log -qr e:
1444 $ hg log -qr e:
1445 6:e0cc66ef77e8
1445 6:e0cc66ef77e8
1446 7:013af1973af4
1446 7:013af1973af4
1447 8:d5d0dcbdc4d9
1447 8:d5d0dcbdc4d9
1448 9:24286f4ae135
1448 9:24286f4ae135
1449
1449
1450 $ hg log -qr :e
1450 $ hg log -qr :e
1451 0:2785f51eece5
1451 0:2785f51eece5
1452 1:d75937da8da0
1452 1:d75937da8da0
1453 2:5ed5505e9f1c
1453 2:5ed5505e9f1c
1454 3:8528aa5637f2
1454 3:8528aa5637f2
1455 4:2326846efdab
1455 4:2326846efdab
1456 5:904fa392b941
1456 5:904fa392b941
1457 6:e0cc66ef77e8
1457 6:e0cc66ef77e8
1458
1458
1459 issue2549 - correct optimizations
1459 issue2549 - correct optimizations
1460
1460
1461 $ log 'limit(1 or 2 or 3, 2) and not 2'
1461 $ log 'limit(1 or 2 or 3, 2) and not 2'
1462 1
1462 1
1463 $ log 'max(1 or 2) and not 2'
1463 $ log 'max(1 or 2) and not 2'
1464 $ log 'min(1 or 2) and not 1'
1464 $ log 'min(1 or 2) and not 1'
1465 $ log 'last(1 or 2, 1) and not 2'
1465 $ log 'last(1 or 2, 1) and not 2'
1466
1466
1467 issue4289 - ordering of built-ins
1467 issue4289 - ordering of built-ins
1468 $ hg log -M -q -r 3:2
1468 $ hg log -M -q -r 3:2
1469 3:8528aa5637f2
1469 3:8528aa5637f2
1470 2:5ed5505e9f1c
1470 2:5ed5505e9f1c
1471
1471
1472 test revsets started with 40-chars hash (issue3669)
1472 test revsets started with 40-chars hash (issue3669)
1473
1473
1474 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1474 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1475 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1475 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1476 9
1476 9
1477 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1477 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1478 8
1478 8
1479
1479
1480 test or-ed indirect predicates (issue3775)
1480 test or-ed indirect predicates (issue3775)
1481
1481
1482 $ log '6 or 6^1' | sort
1482 $ log '6 or 6^1' | sort
1483 5
1483 5
1484 6
1484 6
1485 $ log '6^1 or 6' | sort
1485 $ log '6^1 or 6' | sort
1486 5
1486 5
1487 6
1487 6
1488 $ log '4 or 4~1' | sort
1488 $ log '4 or 4~1' | sort
1489 2
1489 2
1490 4
1490 4
1491 $ log '4~1 or 4' | sort
1491 $ log '4~1 or 4' | sort
1492 2
1492 2
1493 4
1493 4
1494 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1494 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1495 0
1495 0
1496 1
1496 1
1497 2
1497 2
1498 3
1498 3
1499 4
1499 4
1500 5
1500 5
1501 6
1501 6
1502 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1502 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1503 0
1503 0
1504 1
1504 1
1505 2
1505 2
1506 3
1506 3
1507 4
1507 4
1508 5
1508 5
1509 6
1509 6
1510
1510
1511 tests for 'remote()' predicate:
1511 tests for 'remote()' predicate:
1512 #. (csets in remote) (id) (remote)
1512 #. (csets in remote) (id) (remote)
1513 1. less than local current branch "default"
1513 1. less than local current branch "default"
1514 2. same with local specified "default"
1514 2. same with local specified "default"
1515 3. more than local specified specified
1515 3. more than local specified specified
1516
1516
1517 $ hg clone --quiet -U . ../remote3
1517 $ hg clone --quiet -U . ../remote3
1518 $ cd ../remote3
1518 $ cd ../remote3
1519 $ hg update -q 7
1519 $ hg update -q 7
1520 $ echo r > r
1520 $ echo r > r
1521 $ hg ci -Aqm 10
1521 $ hg ci -Aqm 10
1522 $ log 'remote()'
1522 $ log 'remote()'
1523 7
1523 7
1524 $ log 'remote("a-b-c-")'
1524 $ log 'remote("a-b-c-")'
1525 2
1525 2
1526 $ cd ../repo
1526 $ cd ../repo
1527 $ log 'remote(".a.b.c.", "../remote3")'
1527 $ log 'remote(".a.b.c.", "../remote3")'
1528
1528
1529 tests for concatenation of strings/symbols by "##"
1529 tests for concatenation of strings/symbols by "##"
1530
1530
1531 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1531 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1532 (_concat
1532 (_concat
1533 (_concat
1533 (_concat
1534 (_concat
1534 (_concat
1535 ('symbol', '278')
1535 ('symbol', '278')
1536 ('string', '5f5'))
1536 ('string', '5f5'))
1537 ('symbol', '1ee'))
1537 ('symbol', '1ee'))
1538 ('string', 'ce5'))
1538 ('string', 'ce5'))
1539 ('string', '2785f51eece5')
1539 ('string', '2785f51eece5')
1540 * set:
1540 * set:
1541 <baseset [0]>
1541 <baseset [0]>
1542 0
1542 0
1543
1543
1544 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1544 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1545 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1545 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1546 (func
1546 (func
1547 ('symbol', 'cat4')
1547 ('symbol', 'cat4')
1548 (list
1548 (list
1549 (list
1549 (list
1550 (list
1550 (list
1551 ('symbol', '278')
1551 ('symbol', '278')
1552 ('string', '5f5'))
1552 ('string', '5f5'))
1553 ('symbol', '1ee'))
1553 ('symbol', '1ee'))
1554 ('string', 'ce5')))
1554 ('string', 'ce5')))
1555 (_concat
1555 (_concat
1556 (_concat
1556 (_concat
1557 (_concat
1557 (_concat
1558 ('symbol', '278')
1558 ('symbol', '278')
1559 ('string', '5f5'))
1559 ('string', '5f5'))
1560 ('symbol', '1ee'))
1560 ('symbol', '1ee'))
1561 ('string', 'ce5'))
1561 ('string', 'ce5'))
1562 ('string', '2785f51eece5')
1562 ('string', '2785f51eece5')
1563 * set:
1563 * set:
1564 <baseset [0]>
1564 <baseset [0]>
1565 0
1565 0
1566
1566
1567 (check concatenation in alias nesting)
1567 (check concatenation in alias nesting)
1568
1568
1569 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1569 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1570 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1570 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1571 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1571 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1572 0
1572 0
1573
1573
1574 (check operator priority)
1574 (check operator priority)
1575
1575
1576 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1576 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1577 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1577 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1578 0
1578 0
1579 4
1579 4
1580
1580
1581 $ cd ..
1581 $ cd ..
1582
1582
1583 prepare repository that has "default" branches of multiple roots
1583 prepare repository that has "default" branches of multiple roots
1584
1584
1585 $ hg init namedbranch
1585 $ hg init namedbranch
1586 $ cd namedbranch
1586 $ cd namedbranch
1587
1587
1588 $ echo default0 >> a
1588 $ echo default0 >> a
1589 $ hg ci -Aqm0
1589 $ hg ci -Aqm0
1590 $ echo default1 >> a
1590 $ echo default1 >> a
1591 $ hg ci -m1
1591 $ hg ci -m1
1592
1592
1593 $ hg branch -q stable
1593 $ hg branch -q stable
1594 $ echo stable2 >> a
1594 $ echo stable2 >> a
1595 $ hg ci -m2
1595 $ hg ci -m2
1596 $ echo stable3 >> a
1596 $ echo stable3 >> a
1597 $ hg ci -m3
1597 $ hg ci -m3
1598
1598
1599 $ hg update -q null
1599 $ hg update -q null
1600 $ echo default4 >> a
1600 $ echo default4 >> a
1601 $ hg ci -Aqm4
1601 $ hg ci -Aqm4
1602 $ echo default5 >> a
1602 $ echo default5 >> a
1603 $ hg ci -m5
1603 $ hg ci -m5
1604
1604
1605 "null" revision belongs to "default" branch (issue4683)
1606
1607 $ log 'branch(null)'
1608 0
1609 1
1610 4
1611 5
1612
1605 "null" revision belongs to "default" branch, but it shouldn't appear in set
1613 "null" revision belongs to "default" branch, but it shouldn't appear in set
1606 unless explicitly specified (issue4682)
1614 unless explicitly specified (issue4682)
1607
1615
1608 $ log 'children(branch(default))'
1616 $ log 'children(branch(default))'
1609 1
1617 1
1610 2
1618 2
1611 5
1619 5
1612
1620
1613 $ cd ..
1621 $ cd ..
1614
1622
1615 test author/desc/keyword in problematic encoding
1623 test author/desc/keyword in problematic encoding
1616 # unicode: cp932:
1624 # unicode: cp932:
1617 # u30A2 0x83 0x41(= 'A')
1625 # u30A2 0x83 0x41(= 'A')
1618 # u30C2 0x83 0x61(= 'a')
1626 # u30C2 0x83 0x61(= 'a')
1619
1627
1620 $ hg init problematicencoding
1628 $ hg init problematicencoding
1621 $ cd problematicencoding
1629 $ cd problematicencoding
1622
1630
1623 $ python > setup.sh <<EOF
1631 $ python > setup.sh <<EOF
1624 > print u'''
1632 > print u'''
1625 > echo a > text
1633 > echo a > text
1626 > hg add text
1634 > hg add text
1627 > hg --encoding utf-8 commit -u '\u30A2' -m none
1635 > hg --encoding utf-8 commit -u '\u30A2' -m none
1628 > echo b > text
1636 > echo b > text
1629 > hg --encoding utf-8 commit -u '\u30C2' -m none
1637 > hg --encoding utf-8 commit -u '\u30C2' -m none
1630 > echo c > text
1638 > echo c > text
1631 > hg --encoding utf-8 commit -u none -m '\u30A2'
1639 > hg --encoding utf-8 commit -u none -m '\u30A2'
1632 > echo d > text
1640 > echo d > text
1633 > hg --encoding utf-8 commit -u none -m '\u30C2'
1641 > hg --encoding utf-8 commit -u none -m '\u30C2'
1634 > '''.encode('utf-8')
1642 > '''.encode('utf-8')
1635 > EOF
1643 > EOF
1636 $ sh < setup.sh
1644 $ sh < setup.sh
1637
1645
1638 test in problematic encoding
1646 test in problematic encoding
1639 $ python > test.sh <<EOF
1647 $ python > test.sh <<EOF
1640 > print u'''
1648 > print u'''
1641 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1649 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1642 > echo ====
1650 > echo ====
1643 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1651 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1644 > echo ====
1652 > echo ====
1645 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1653 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1646 > echo ====
1654 > echo ====
1647 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1655 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1648 > echo ====
1656 > echo ====
1649 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1657 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1650 > echo ====
1658 > echo ====
1651 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1659 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1652 > '''.encode('cp932')
1660 > '''.encode('cp932')
1653 > EOF
1661 > EOF
1654 $ sh < test.sh
1662 $ sh < test.sh
1655 0
1663 0
1656 ====
1664 ====
1657 1
1665 1
1658 ====
1666 ====
1659 2
1667 2
1660 ====
1668 ====
1661 3
1669 3
1662 ====
1670 ====
1663 0
1671 0
1664 2
1672 2
1665 ====
1673 ====
1666 1
1674 1
1667 3
1675 3
1668
1676
1669 test error message of bad revset
1677 test error message of bad revset
1670 $ hg log -r 'foo\\'
1678 $ hg log -r 'foo\\'
1671 hg: parse error at 3: syntax error in revset 'foo\\'
1679 hg: parse error at 3: syntax error in revset 'foo\\'
1672 [255]
1680 [255]
1673
1681
1674 $ cd ..
1682 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now