##// END OF EJS Templates
branchmap: handle nullrev in setcachedata...
Durham Goode -
r31454:a5bad127 default
parent child Browse files
Show More
@@ -1,519 +1,521 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import struct
10 import struct
11
11
12 from .node import (
12 from .node import (
13 bin,
13 bin,
14 hex,
14 hex,
15 nullid,
15 nullid,
16 nullrev,
16 nullrev,
17 )
17 )
18 from . import (
18 from . import (
19 encoding,
19 encoding,
20 error,
20 error,
21 scmutil,
21 scmutil,
22 util,
22 util,
23 )
23 )
24
24
25 calcsize = struct.calcsize
25 calcsize = struct.calcsize
26 pack_into = struct.pack_into
26 pack_into = struct.pack_into
27 unpack_from = struct.unpack_from
27 unpack_from = struct.unpack_from
28
28
29 def _filename(repo):
29 def _filename(repo):
30 """name of a branchcache file for a given repo or repoview"""
30 """name of a branchcache file for a given repo or repoview"""
31 filename = "cache/branch2"
31 filename = "cache/branch2"
32 if repo.filtername:
32 if repo.filtername:
33 filename = '%s-%s' % (filename, repo.filtername)
33 filename = '%s-%s' % (filename, repo.filtername)
34 return filename
34 return filename
35
35
36 def read(repo):
36 def read(repo):
37 try:
37 try:
38 f = repo.vfs(_filename(repo))
38 f = repo.vfs(_filename(repo))
39 lines = f.read().split('\n')
39 lines = f.read().split('\n')
40 f.close()
40 f.close()
41 except (IOError, OSError):
41 except (IOError, OSError):
42 return None
42 return None
43
43
44 try:
44 try:
45 cachekey = lines.pop(0).split(" ", 2)
45 cachekey = lines.pop(0).split(" ", 2)
46 last, lrev = cachekey[:2]
46 last, lrev = cachekey[:2]
47 last, lrev = bin(last), int(lrev)
47 last, lrev = bin(last), int(lrev)
48 filteredhash = None
48 filteredhash = None
49 if len(cachekey) > 2:
49 if len(cachekey) > 2:
50 filteredhash = bin(cachekey[2])
50 filteredhash = bin(cachekey[2])
51 partial = branchcache(tipnode=last, tiprev=lrev,
51 partial = branchcache(tipnode=last, tiprev=lrev,
52 filteredhash=filteredhash)
52 filteredhash=filteredhash)
53 if not partial.validfor(repo):
53 if not partial.validfor(repo):
54 # invalidate the cache
54 # invalidate the cache
55 raise ValueError('tip differs')
55 raise ValueError('tip differs')
56 cl = repo.changelog
56 cl = repo.changelog
57 for l in lines:
57 for l in lines:
58 if not l:
58 if not l:
59 continue
59 continue
60 node, state, label = l.split(" ", 2)
60 node, state, label = l.split(" ", 2)
61 if state not in 'oc':
61 if state not in 'oc':
62 raise ValueError('invalid branch state')
62 raise ValueError('invalid branch state')
63 label = encoding.tolocal(label.strip())
63 label = encoding.tolocal(label.strip())
64 node = bin(node)
64 node = bin(node)
65 if not cl.hasnode(node):
65 if not cl.hasnode(node):
66 raise ValueError('node %s does not exist' % hex(node))
66 raise ValueError('node %s does not exist' % hex(node))
67 partial.setdefault(label, []).append(node)
67 partial.setdefault(label, []).append(node)
68 if state == 'c':
68 if state == 'c':
69 partial._closednodes.add(node)
69 partial._closednodes.add(node)
70 except KeyboardInterrupt:
70 except KeyboardInterrupt:
71 raise
71 raise
72 except Exception as inst:
72 except Exception as inst:
73 if repo.ui.debugflag:
73 if repo.ui.debugflag:
74 msg = 'invalid branchheads cache'
74 msg = 'invalid branchheads cache'
75 if repo.filtername is not None:
75 if repo.filtername is not None:
76 msg += ' (%s)' % repo.filtername
76 msg += ' (%s)' % repo.filtername
77 msg += ': %s\n'
77 msg += ': %s\n'
78 repo.ui.debug(msg % inst)
78 repo.ui.debug(msg % inst)
79 partial = None
79 partial = None
80 return partial
80 return partial
81
81
82 ### Nearest subset relation
82 ### Nearest subset relation
83 # Nearest subset of filter X is a filter Y so that:
83 # Nearest subset of filter X is a filter Y so that:
84 # * Y is included in X,
84 # * Y is included in X,
85 # * X - Y is as small as possible.
85 # * X - Y is as small as possible.
86 # This create and ordering used for branchmap purpose.
86 # This create and ordering used for branchmap purpose.
87 # the ordering may be partial
87 # the ordering may be partial
88 subsettable = {None: 'visible',
88 subsettable = {None: 'visible',
89 'visible': 'served',
89 'visible': 'served',
90 'served': 'immutable',
90 'served': 'immutable',
91 'immutable': 'base'}
91 'immutable': 'base'}
92
92
93 def updatecache(repo):
93 def updatecache(repo):
94 cl = repo.changelog
94 cl = repo.changelog
95 filtername = repo.filtername
95 filtername = repo.filtername
96 partial = repo._branchcaches.get(filtername)
96 partial = repo._branchcaches.get(filtername)
97
97
98 revs = []
98 revs = []
99 if partial is None or not partial.validfor(repo):
99 if partial is None or not partial.validfor(repo):
100 partial = read(repo)
100 partial = read(repo)
101 if partial is None:
101 if partial is None:
102 subsetname = subsettable.get(filtername)
102 subsetname = subsettable.get(filtername)
103 if subsetname is None:
103 if subsetname is None:
104 partial = branchcache()
104 partial = branchcache()
105 else:
105 else:
106 subset = repo.filtered(subsetname)
106 subset = repo.filtered(subsetname)
107 partial = subset.branchmap().copy()
107 partial = subset.branchmap().copy()
108 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
108 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
109 revs.extend(r for r in extrarevs if r <= partial.tiprev)
109 revs.extend(r for r in extrarevs if r <= partial.tiprev)
110 revs.extend(cl.revs(start=partial.tiprev + 1))
110 revs.extend(cl.revs(start=partial.tiprev + 1))
111 if revs:
111 if revs:
112 partial.update(repo, revs)
112 partial.update(repo, revs)
113 partial.write(repo)
113 partial.write(repo)
114
114
115 assert partial.validfor(repo), filtername
115 assert partial.validfor(repo), filtername
116 repo._branchcaches[repo.filtername] = partial
116 repo._branchcaches[repo.filtername] = partial
117
117
118 def replacecache(repo, bm):
118 def replacecache(repo, bm):
119 """Replace the branchmap cache for a repo with a branch mapping.
119 """Replace the branchmap cache for a repo with a branch mapping.
120
120
121 This is likely only called during clone with a branch map from a remote.
121 This is likely only called during clone with a branch map from a remote.
122 """
122 """
123 rbheads = []
123 rbheads = []
124 closed = []
124 closed = []
125 for bheads in bm.itervalues():
125 for bheads in bm.itervalues():
126 rbheads.extend(bheads)
126 rbheads.extend(bheads)
127 for h in bheads:
127 for h in bheads:
128 r = repo.changelog.rev(h)
128 r = repo.changelog.rev(h)
129 b, c = repo.changelog.branchinfo(r)
129 b, c = repo.changelog.branchinfo(r)
130 if c:
130 if c:
131 closed.append(h)
131 closed.append(h)
132
132
133 if rbheads:
133 if rbheads:
134 rtiprev = max((int(repo.changelog.rev(node))
134 rtiprev = max((int(repo.changelog.rev(node))
135 for node in rbheads))
135 for node in rbheads))
136 cache = branchcache(bm,
136 cache = branchcache(bm,
137 repo[rtiprev].node(),
137 repo[rtiprev].node(),
138 rtiprev,
138 rtiprev,
139 closednodes=closed)
139 closednodes=closed)
140
140
141 # Try to stick it as low as possible
141 # Try to stick it as low as possible
142 # filter above served are unlikely to be fetch from a clone
142 # filter above served are unlikely to be fetch from a clone
143 for candidate in ('base', 'immutable', 'served'):
143 for candidate in ('base', 'immutable', 'served'):
144 rview = repo.filtered(candidate)
144 rview = repo.filtered(candidate)
145 if cache.validfor(rview):
145 if cache.validfor(rview):
146 repo._branchcaches[candidate] = cache
146 repo._branchcaches[candidate] = cache
147 cache.write(rview)
147 cache.write(rview)
148 break
148 break
149
149
150 class branchcache(dict):
150 class branchcache(dict):
151 """A dict like object that hold branches heads cache.
151 """A dict like object that hold branches heads cache.
152
152
153 This cache is used to avoid costly computations to determine all the
153 This cache is used to avoid costly computations to determine all the
154 branch heads of a repo.
154 branch heads of a repo.
155
155
156 The cache is serialized on disk in the following format:
156 The cache is serialized on disk in the following format:
157
157
158 <tip hex node> <tip rev number> [optional filtered repo hex hash]
158 <tip hex node> <tip rev number> [optional filtered repo hex hash]
159 <branch head hex node> <open/closed state> <branch name>
159 <branch head hex node> <open/closed state> <branch name>
160 <branch head hex node> <open/closed state> <branch name>
160 <branch head hex node> <open/closed state> <branch name>
161 ...
161 ...
162
162
163 The first line is used to check if the cache is still valid. If the
163 The first line is used to check if the cache is still valid. If the
164 branch cache is for a filtered repo view, an optional third hash is
164 branch cache is for a filtered repo view, an optional third hash is
165 included that hashes the hashes of all filtered revisions.
165 included that hashes the hashes of all filtered revisions.
166
166
167 The open/closed state is represented by a single letter 'o' or 'c'.
167 The open/closed state is represented by a single letter 'o' or 'c'.
168 This field can be used to avoid changelog reads when determining if a
168 This field can be used to avoid changelog reads when determining if a
169 branch head closes a branch or not.
169 branch head closes a branch or not.
170 """
170 """
171
171
172 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
172 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
173 filteredhash=None, closednodes=None):
173 filteredhash=None, closednodes=None):
174 super(branchcache, self).__init__(entries)
174 super(branchcache, self).__init__(entries)
175 self.tipnode = tipnode
175 self.tipnode = tipnode
176 self.tiprev = tiprev
176 self.tiprev = tiprev
177 self.filteredhash = filteredhash
177 self.filteredhash = filteredhash
178 # closednodes is a set of nodes that close their branch. If the branch
178 # closednodes is a set of nodes that close their branch. If the branch
179 # cache has been updated, it may contain nodes that are no longer
179 # cache has been updated, it may contain nodes that are no longer
180 # heads.
180 # heads.
181 if closednodes is None:
181 if closednodes is None:
182 self._closednodes = set()
182 self._closednodes = set()
183 else:
183 else:
184 self._closednodes = closednodes
184 self._closednodes = closednodes
185
185
186 def validfor(self, repo):
186 def validfor(self, repo):
187 """Is the cache content valid regarding a repo
187 """Is the cache content valid regarding a repo
188
188
189 - False when cached tipnode is unknown or if we detect a strip.
189 - False when cached tipnode is unknown or if we detect a strip.
190 - True when cache is up to date or a subset of current repo."""
190 - True when cache is up to date or a subset of current repo."""
191 try:
191 try:
192 return ((self.tipnode == repo.changelog.node(self.tiprev))
192 return ((self.tipnode == repo.changelog.node(self.tiprev))
193 and (self.filteredhash == \
193 and (self.filteredhash == \
194 scmutil.filteredhash(repo, self.tiprev)))
194 scmutil.filteredhash(repo, self.tiprev)))
195 except IndexError:
195 except IndexError:
196 return False
196 return False
197
197
198 def _branchtip(self, heads):
198 def _branchtip(self, heads):
199 '''Return tuple with last open head in heads and false,
199 '''Return tuple with last open head in heads and false,
200 otherwise return last closed head and true.'''
200 otherwise return last closed head and true.'''
201 tip = heads[-1]
201 tip = heads[-1]
202 closed = True
202 closed = True
203 for h in reversed(heads):
203 for h in reversed(heads):
204 if h not in self._closednodes:
204 if h not in self._closednodes:
205 tip = h
205 tip = h
206 closed = False
206 closed = False
207 break
207 break
208 return tip, closed
208 return tip, closed
209
209
210 def branchtip(self, branch):
210 def branchtip(self, branch):
211 '''Return the tipmost open head on branch head, otherwise return the
211 '''Return the tipmost open head on branch head, otherwise return the
212 tipmost closed head on branch.
212 tipmost closed head on branch.
213 Raise KeyError for unknown branch.'''
213 Raise KeyError for unknown branch.'''
214 return self._branchtip(self[branch])[0]
214 return self._branchtip(self[branch])[0]
215
215
216 def branchheads(self, branch, closed=False):
216 def branchheads(self, branch, closed=False):
217 heads = self[branch]
217 heads = self[branch]
218 if not closed:
218 if not closed:
219 heads = [h for h in heads if h not in self._closednodes]
219 heads = [h for h in heads if h not in self._closednodes]
220 return heads
220 return heads
221
221
222 def iterbranches(self):
222 def iterbranches(self):
223 for bn, heads in self.iteritems():
223 for bn, heads in self.iteritems():
224 yield (bn, heads) + self._branchtip(heads)
224 yield (bn, heads) + self._branchtip(heads)
225
225
226 def copy(self):
226 def copy(self):
227 """return an deep copy of the branchcache object"""
227 """return an deep copy of the branchcache object"""
228 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
228 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
229 self._closednodes)
229 self._closednodes)
230
230
231 def write(self, repo):
231 def write(self, repo):
232 try:
232 try:
233 f = repo.vfs(_filename(repo), "w", atomictemp=True)
233 f = repo.vfs(_filename(repo), "w", atomictemp=True)
234 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
234 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
235 if self.filteredhash is not None:
235 if self.filteredhash is not None:
236 cachekey.append(hex(self.filteredhash))
236 cachekey.append(hex(self.filteredhash))
237 f.write(" ".join(cachekey) + '\n')
237 f.write(" ".join(cachekey) + '\n')
238 nodecount = 0
238 nodecount = 0
239 for label, nodes in sorted(self.iteritems()):
239 for label, nodes in sorted(self.iteritems()):
240 for node in nodes:
240 for node in nodes:
241 nodecount += 1
241 nodecount += 1
242 if node in self._closednodes:
242 if node in self._closednodes:
243 state = 'c'
243 state = 'c'
244 else:
244 else:
245 state = 'o'
245 state = 'o'
246 f.write("%s %s %s\n" % (hex(node), state,
246 f.write("%s %s %s\n" % (hex(node), state,
247 encoding.fromlocal(label)))
247 encoding.fromlocal(label)))
248 f.close()
248 f.close()
249 repo.ui.log('branchcache',
249 repo.ui.log('branchcache',
250 'wrote %s branch cache with %d labels and %d nodes\n',
250 'wrote %s branch cache with %d labels and %d nodes\n',
251 repo.filtername, len(self), nodecount)
251 repo.filtername, len(self), nodecount)
252 except (IOError, OSError, error.Abort) as inst:
252 except (IOError, OSError, error.Abort) as inst:
253 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
253 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
254 # Abort may be raise by read only opener
254 # Abort may be raise by read only opener
255 pass
255 pass
256
256
257 def update(self, repo, revgen):
257 def update(self, repo, revgen):
258 """Given a branchhead cache, self, that may have extra nodes or be
258 """Given a branchhead cache, self, that may have extra nodes or be
259 missing heads, and a generator of nodes that are strictly a superset of
259 missing heads, and a generator of nodes that are strictly a superset of
260 heads missing, this function updates self to be correct.
260 heads missing, this function updates self to be correct.
261 """
261 """
262 starttime = util.timer()
262 starttime = util.timer()
263 cl = repo.changelog
263 cl = repo.changelog
264 # collect new branch entries
264 # collect new branch entries
265 newbranches = {}
265 newbranches = {}
266 getbranchinfo = repo.revbranchcache().branchinfo
266 getbranchinfo = repo.revbranchcache().branchinfo
267 for r in revgen:
267 for r in revgen:
268 branch, closesbranch = getbranchinfo(r)
268 branch, closesbranch = getbranchinfo(r)
269 newbranches.setdefault(branch, []).append(r)
269 newbranches.setdefault(branch, []).append(r)
270 if closesbranch:
270 if closesbranch:
271 self._closednodes.add(cl.node(r))
271 self._closednodes.add(cl.node(r))
272
272
273 # fetch current topological heads to speed up filtering
273 # fetch current topological heads to speed up filtering
274 topoheads = set(cl.headrevs())
274 topoheads = set(cl.headrevs())
275
275
276 # if older branchheads are reachable from new ones, they aren't
276 # if older branchheads are reachable from new ones, they aren't
277 # really branchheads. Note checking parents is insufficient:
277 # really branchheads. Note checking parents is insufficient:
278 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
278 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
279 for branch, newheadrevs in newbranches.iteritems():
279 for branch, newheadrevs in newbranches.iteritems():
280 bheads = self.setdefault(branch, [])
280 bheads = self.setdefault(branch, [])
281 bheadset = set(cl.rev(node) for node in bheads)
281 bheadset = set(cl.rev(node) for node in bheads)
282
282
283 # This have been tested True on all internal usage of this function.
283 # This have been tested True on all internal usage of this function.
284 # run it again in case of doubt
284 # run it again in case of doubt
285 # assert not (set(bheadrevs) & set(newheadrevs))
285 # assert not (set(bheadrevs) & set(newheadrevs))
286 newheadrevs.sort()
286 newheadrevs.sort()
287 bheadset.update(newheadrevs)
287 bheadset.update(newheadrevs)
288
288
289 # This prunes out two kinds of heads - heads that are superseded by
289 # This prunes out two kinds of heads - heads that are superseded by
290 # a head in newheadrevs, and newheadrevs that are not heads because
290 # a head in newheadrevs, and newheadrevs that are not heads because
291 # an existing head is their descendant.
291 # an existing head is their descendant.
292 uncertain = bheadset - topoheads
292 uncertain = bheadset - topoheads
293 if uncertain:
293 if uncertain:
294 floorrev = min(uncertain)
294 floorrev = min(uncertain)
295 ancestors = set(cl.ancestors(newheadrevs, floorrev))
295 ancestors = set(cl.ancestors(newheadrevs, floorrev))
296 bheadset -= ancestors
296 bheadset -= ancestors
297 bheadrevs = sorted(bheadset)
297 bheadrevs = sorted(bheadset)
298 self[branch] = [cl.node(rev) for rev in bheadrevs]
298 self[branch] = [cl.node(rev) for rev in bheadrevs]
299 tiprev = bheadrevs[-1]
299 tiprev = bheadrevs[-1]
300 if tiprev > self.tiprev:
300 if tiprev > self.tiprev:
301 self.tipnode = cl.node(tiprev)
301 self.tipnode = cl.node(tiprev)
302 self.tiprev = tiprev
302 self.tiprev = tiprev
303
303
304 if not self.validfor(repo):
304 if not self.validfor(repo):
305 # cache key are not valid anymore
305 # cache key are not valid anymore
306 self.tipnode = nullid
306 self.tipnode = nullid
307 self.tiprev = nullrev
307 self.tiprev = nullrev
308 for heads in self.values():
308 for heads in self.values():
309 tiprev = max(cl.rev(node) for node in heads)
309 tiprev = max(cl.rev(node) for node in heads)
310 if tiprev > self.tiprev:
310 if tiprev > self.tiprev:
311 self.tipnode = cl.node(tiprev)
311 self.tipnode = cl.node(tiprev)
312 self.tiprev = tiprev
312 self.tiprev = tiprev
313 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
313 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
314
314
315 duration = util.timer() - starttime
315 duration = util.timer() - starttime
316 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
316 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
317 repo.filtername, duration)
317 repo.filtername, duration)
318
318
319 # Revision branch info cache
319 # Revision branch info cache
320
320
321 _rbcversion = '-v1'
321 _rbcversion = '-v1'
322 _rbcnames = 'cache/rbc-names' + _rbcversion
322 _rbcnames = 'cache/rbc-names' + _rbcversion
323 _rbcrevs = 'cache/rbc-revs' + _rbcversion
323 _rbcrevs = 'cache/rbc-revs' + _rbcversion
324 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
324 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
325 _rbcrecfmt = '>4sI'
325 _rbcrecfmt = '>4sI'
326 _rbcrecsize = calcsize(_rbcrecfmt)
326 _rbcrecsize = calcsize(_rbcrecfmt)
327 _rbcnodelen = 4
327 _rbcnodelen = 4
328 _rbcbranchidxmask = 0x7fffffff
328 _rbcbranchidxmask = 0x7fffffff
329 _rbccloseflag = 0x80000000
329 _rbccloseflag = 0x80000000
330
330
331 class revbranchcache(object):
331 class revbranchcache(object):
332 """Persistent cache, mapping from revision number to branch name and close.
332 """Persistent cache, mapping from revision number to branch name and close.
333 This is a low level cache, independent of filtering.
333 This is a low level cache, independent of filtering.
334
334
335 Branch names are stored in rbc-names in internal encoding separated by 0.
335 Branch names are stored in rbc-names in internal encoding separated by 0.
336 rbc-names is append-only, and each branch name is only stored once and will
336 rbc-names is append-only, and each branch name is only stored once and will
337 thus have a unique index.
337 thus have a unique index.
338
338
339 The branch info for each revision is stored in rbc-revs as constant size
339 The branch info for each revision is stored in rbc-revs as constant size
340 records. The whole file is read into memory, but it is only 'parsed' on
340 records. The whole file is read into memory, but it is only 'parsed' on
341 demand. The file is usually append-only but will be truncated if repo
341 demand. The file is usually append-only but will be truncated if repo
342 modification is detected.
342 modification is detected.
343 The record for each revision contains the first 4 bytes of the
343 The record for each revision contains the first 4 bytes of the
344 corresponding node hash, and the record is only used if it still matches.
344 corresponding node hash, and the record is only used if it still matches.
345 Even a completely trashed rbc-revs fill thus still give the right result
345 Even a completely trashed rbc-revs fill thus still give the right result
346 while converging towards full recovery ... assuming no incorrectly matching
346 while converging towards full recovery ... assuming no incorrectly matching
347 node hashes.
347 node hashes.
348 The record also contains 4 bytes where 31 bits contains the index of the
348 The record also contains 4 bytes where 31 bits contains the index of the
349 branch and the last bit indicate that it is a branch close commit.
349 branch and the last bit indicate that it is a branch close commit.
350 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
350 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
351 and will grow with it but be 1/8th of its size.
351 and will grow with it but be 1/8th of its size.
352 """
352 """
353
353
354 def __init__(self, repo, readonly=True):
354 def __init__(self, repo, readonly=True):
355 assert repo.filtername is None
355 assert repo.filtername is None
356 self._repo = repo
356 self._repo = repo
357 self._names = [] # branch names in local encoding with static index
357 self._names = [] # branch names in local encoding with static index
358 self._rbcrevs = bytearray()
358 self._rbcrevs = bytearray()
359 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
359 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
360 try:
360 try:
361 bndata = repo.vfs.read(_rbcnames)
361 bndata = repo.vfs.read(_rbcnames)
362 self._rbcsnameslen = len(bndata) # for verification before writing
362 self._rbcsnameslen = len(bndata) # for verification before writing
363 if bndata:
363 if bndata:
364 self._names = [encoding.tolocal(bn)
364 self._names = [encoding.tolocal(bn)
365 for bn in bndata.split('\0')]
365 for bn in bndata.split('\0')]
366 except (IOError, OSError):
366 except (IOError, OSError):
367 if readonly:
367 if readonly:
368 # don't try to use cache - fall back to the slow path
368 # don't try to use cache - fall back to the slow path
369 self.branchinfo = self._branchinfo
369 self.branchinfo = self._branchinfo
370
370
371 if self._names:
371 if self._names:
372 try:
372 try:
373 data = repo.vfs.read(_rbcrevs)
373 data = repo.vfs.read(_rbcrevs)
374 self._rbcrevs[:] = data
374 self._rbcrevs[:] = data
375 except (IOError, OSError) as inst:
375 except (IOError, OSError) as inst:
376 repo.ui.debug("couldn't read revision branch cache: %s\n" %
376 repo.ui.debug("couldn't read revision branch cache: %s\n" %
377 inst)
377 inst)
378 # remember number of good records on disk
378 # remember number of good records on disk
379 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
379 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
380 len(repo.changelog))
380 len(repo.changelog))
381 if self._rbcrevslen == 0:
381 if self._rbcrevslen == 0:
382 self._names = []
382 self._names = []
383 self._rbcnamescount = len(self._names) # number of names read at
383 self._rbcnamescount = len(self._names) # number of names read at
384 # _rbcsnameslen
384 # _rbcsnameslen
385 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
385 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
386
386
387 def _clear(self):
387 def _clear(self):
388 self._rbcsnameslen = 0
388 self._rbcsnameslen = 0
389 del self._names[:]
389 del self._names[:]
390 self._rbcnamescount = 0
390 self._rbcnamescount = 0
391 self._namesreverse.clear()
391 self._namesreverse.clear()
392 self._rbcrevslen = len(self._repo.changelog)
392 self._rbcrevslen = len(self._repo.changelog)
393 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
393 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
394
394
395 def branchinfo(self, rev):
395 def branchinfo(self, rev):
396 """Return branch name and close flag for rev, using and updating
396 """Return branch name and close flag for rev, using and updating
397 persistent cache."""
397 persistent cache."""
398 changelog = self._repo.changelog
398 changelog = self._repo.changelog
399 rbcrevidx = rev * _rbcrecsize
399 rbcrevidx = rev * _rbcrecsize
400
400
401 # avoid negative index, changelog.read(nullrev) is fast without cache
401 # avoid negative index, changelog.read(nullrev) is fast without cache
402 if rev == nullrev:
402 if rev == nullrev:
403 return changelog.branchinfo(rev)
403 return changelog.branchinfo(rev)
404
404
405 # if requested rev isn't allocated, grow and cache the rev info
405 # if requested rev isn't allocated, grow and cache the rev info
406 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
406 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
407 return self._branchinfo(rev)
407 return self._branchinfo(rev)
408
408
409 # fast path: extract data from cache, use it if node is matching
409 # fast path: extract data from cache, use it if node is matching
410 reponode = changelog.node(rev)[:_rbcnodelen]
410 reponode = changelog.node(rev)[:_rbcnodelen]
411 cachenode, branchidx = unpack_from(
411 cachenode, branchidx = unpack_from(
412 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx)
412 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx)
413 close = bool(branchidx & _rbccloseflag)
413 close = bool(branchidx & _rbccloseflag)
414 if close:
414 if close:
415 branchidx &= _rbcbranchidxmask
415 branchidx &= _rbcbranchidxmask
416 if cachenode == '\0\0\0\0':
416 if cachenode == '\0\0\0\0':
417 pass
417 pass
418 elif cachenode == reponode:
418 elif cachenode == reponode:
419 try:
419 try:
420 return self._names[branchidx], close
420 return self._names[branchidx], close
421 except IndexError:
421 except IndexError:
422 # recover from invalid reference to unknown branch
422 # recover from invalid reference to unknown branch
423 self._repo.ui.debug("referenced branch names not found"
423 self._repo.ui.debug("referenced branch names not found"
424 " - rebuilding revision branch cache from scratch\n")
424 " - rebuilding revision branch cache from scratch\n")
425 self._clear()
425 self._clear()
426 else:
426 else:
427 # rev/node map has changed, invalidate the cache from here up
427 # rev/node map has changed, invalidate the cache from here up
428 self._repo.ui.debug("history modification detected - truncating "
428 self._repo.ui.debug("history modification detected - truncating "
429 "revision branch cache to revision %s\n" % rev)
429 "revision branch cache to revision %s\n" % rev)
430 truncate = rbcrevidx + _rbcrecsize
430 truncate = rbcrevidx + _rbcrecsize
431 del self._rbcrevs[truncate:]
431 del self._rbcrevs[truncate:]
432 self._rbcrevslen = min(self._rbcrevslen, truncate)
432 self._rbcrevslen = min(self._rbcrevslen, truncate)
433
433
434 # fall back to slow path and make sure it will be written to disk
434 # fall back to slow path and make sure it will be written to disk
435 return self._branchinfo(rev)
435 return self._branchinfo(rev)
436
436
437 def _branchinfo(self, rev):
437 def _branchinfo(self, rev):
438 """Retrieve branch info from changelog and update _rbcrevs"""
438 """Retrieve branch info from changelog and update _rbcrevs"""
439 changelog = self._repo.changelog
439 changelog = self._repo.changelog
440 b, close = changelog.branchinfo(rev)
440 b, close = changelog.branchinfo(rev)
441 if b in self._namesreverse:
441 if b in self._namesreverse:
442 branchidx = self._namesreverse[b]
442 branchidx = self._namesreverse[b]
443 else:
443 else:
444 branchidx = len(self._names)
444 branchidx = len(self._names)
445 self._names.append(b)
445 self._names.append(b)
446 self._namesreverse[b] = branchidx
446 self._namesreverse[b] = branchidx
447 reponode = changelog.node(rev)
447 reponode = changelog.node(rev)
448 if close:
448 if close:
449 branchidx |= _rbccloseflag
449 branchidx |= _rbccloseflag
450 self._setcachedata(rev, reponode, branchidx)
450 self._setcachedata(rev, reponode, branchidx)
451 return b, close
451 return b, close
452
452
453 def _setcachedata(self, rev, node, branchidx):
453 def _setcachedata(self, rev, node, branchidx):
454 """Writes the node's branch data to the in-memory cache data."""
454 """Writes the node's branch data to the in-memory cache data."""
455 if rev == nullrev:
456 return
455 rbcrevidx = rev * _rbcrecsize
457 rbcrevidx = rev * _rbcrecsize
456 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
458 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
457 self._rbcrevs.extend('\0' *
459 self._rbcrevs.extend('\0' *
458 (len(self._repo.changelog) * _rbcrecsize -
460 (len(self._repo.changelog) * _rbcrecsize -
459 len(self._rbcrevs)))
461 len(self._rbcrevs)))
460 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
462 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
461 self._rbcrevslen = min(self._rbcrevslen, rev)
463 self._rbcrevslen = min(self._rbcrevslen, rev)
462
464
463 tr = self._repo.currenttransaction()
465 tr = self._repo.currenttransaction()
464 if tr:
466 if tr:
465 tr.addfinalize('write-revbranchcache', self.write)
467 tr.addfinalize('write-revbranchcache', self.write)
466
468
467 def write(self, tr=None):
469 def write(self, tr=None):
468 """Save branch cache if it is dirty."""
470 """Save branch cache if it is dirty."""
469 repo = self._repo
471 repo = self._repo
470 wlock = None
472 wlock = None
471 step = ''
473 step = ''
472 try:
474 try:
473 if self._rbcnamescount < len(self._names):
475 if self._rbcnamescount < len(self._names):
474 step = ' names'
476 step = ' names'
475 wlock = repo.wlock(wait=False)
477 wlock = repo.wlock(wait=False)
476 if self._rbcnamescount != 0:
478 if self._rbcnamescount != 0:
477 f = repo.vfs.open(_rbcnames, 'ab')
479 f = repo.vfs.open(_rbcnames, 'ab')
478 if f.tell() == self._rbcsnameslen:
480 if f.tell() == self._rbcsnameslen:
479 f.write('\0')
481 f.write('\0')
480 else:
482 else:
481 f.close()
483 f.close()
482 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
484 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
483 self._rbcnamescount = 0
485 self._rbcnamescount = 0
484 self._rbcrevslen = 0
486 self._rbcrevslen = 0
485 if self._rbcnamescount == 0:
487 if self._rbcnamescount == 0:
486 # before rewriting names, make sure references are removed
488 # before rewriting names, make sure references are removed
487 repo.vfs.unlinkpath(_rbcrevs, ignoremissing=True)
489 repo.vfs.unlinkpath(_rbcrevs, ignoremissing=True)
488 f = repo.vfs.open(_rbcnames, 'wb')
490 f = repo.vfs.open(_rbcnames, 'wb')
489 f.write('\0'.join(encoding.fromlocal(b)
491 f.write('\0'.join(encoding.fromlocal(b)
490 for b in self._names[self._rbcnamescount:]))
492 for b in self._names[self._rbcnamescount:]))
491 self._rbcsnameslen = f.tell()
493 self._rbcsnameslen = f.tell()
492 f.close()
494 f.close()
493 self._rbcnamescount = len(self._names)
495 self._rbcnamescount = len(self._names)
494
496
495 start = self._rbcrevslen * _rbcrecsize
497 start = self._rbcrevslen * _rbcrecsize
496 if start != len(self._rbcrevs):
498 if start != len(self._rbcrevs):
497 step = ''
499 step = ''
498 if wlock is None:
500 if wlock is None:
499 wlock = repo.wlock(wait=False)
501 wlock = repo.wlock(wait=False)
500 revs = min(len(repo.changelog),
502 revs = min(len(repo.changelog),
501 len(self._rbcrevs) // _rbcrecsize)
503 len(self._rbcrevs) // _rbcrecsize)
502 f = repo.vfs.open(_rbcrevs, 'ab')
504 f = repo.vfs.open(_rbcrevs, 'ab')
503 if f.tell() != start:
505 if f.tell() != start:
504 repo.ui.debug("truncating %s to %s\n" % (_rbcrevs, start))
506 repo.ui.debug("truncating %s to %s\n" % (_rbcrevs, start))
505 f.seek(start)
507 f.seek(start)
506 if f.tell() != start:
508 if f.tell() != start:
507 start = 0
509 start = 0
508 f.seek(start)
510 f.seek(start)
509 f.truncate()
511 f.truncate()
510 end = revs * _rbcrecsize
512 end = revs * _rbcrecsize
511 f.write(self._rbcrevs[start:end])
513 f.write(self._rbcrevs[start:end])
512 f.close()
514 f.close()
513 self._rbcrevslen = revs
515 self._rbcrevslen = revs
514 except (IOError, OSError, error.Abort, error.LockError) as inst:
516 except (IOError, OSError, error.Abort, error.LockError) as inst:
515 repo.ui.debug("couldn't write revision branch cache%s: %s\n"
517 repo.ui.debug("couldn't write revision branch cache%s: %s\n"
516 % (step, inst))
518 % (step, inst))
517 finally:
519 finally:
518 if wlock is not None:
520 if wlock is not None:
519 wlock.release()
521 wlock.release()
@@ -1,722 +1,727 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
7 Basic test
3 $ echo 'root' >root
8 $ echo 'root' >root
4 $ hg add root
9 $ hg add root
5 $ hg commit -d '0 0' -m "Adding root node"
10 $ hg commit -d '0 0' -m "Adding root node"
6
11
7 $ echo 'a' >a
12 $ echo 'a' >a
8 $ hg add a
13 $ hg add a
9 $ hg branch a
14 $ hg branch a
10 marked working directory as branch a
15 marked working directory as branch a
11 (branches are permanent and global, did you want a bookmark?)
16 (branches are permanent and global, did you want a bookmark?)
12 $ hg commit -d '1 0' -m "Adding a branch"
17 $ hg commit -d '1 0' -m "Adding a branch"
13
18
14 $ hg branch q
19 $ hg branch q
15 marked working directory as branch q
20 marked working directory as branch q
16 $ echo 'aa' >a
21 $ echo 'aa' >a
17 $ hg branch -C
22 $ hg branch -C
18 reset working directory to branch a
23 reset working directory to branch a
19 $ hg commit -d '2 0' -m "Adding to a branch"
24 $ hg commit -d '2 0' -m "Adding to a branch"
20
25
21 $ hg update -C 0
26 $ hg update -C 0
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23 $ echo 'b' >b
28 $ echo 'b' >b
24 $ hg add b
29 $ hg add b
25 $ hg branch b
30 $ hg branch b
26 marked working directory as branch b
31 marked working directory as branch b
27 $ hg commit -d '2 0' -m "Adding b branch"
32 $ hg commit -d '2 0' -m "Adding b branch"
28
33
29 $ echo 'bh1' >bh1
34 $ echo 'bh1' >bh1
30 $ hg add bh1
35 $ hg add bh1
31 $ hg commit -d '3 0' -m "Adding b branch head 1"
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
32
37
33 $ hg update -C 2
38 $ hg update -C 2
34 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 $ echo 'bh2' >bh2
40 $ echo 'bh2' >bh2
36 $ hg add bh2
41 $ hg add bh2
37 $ hg commit -d '4 0' -m "Adding b branch head 2"
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
38
43
39 $ echo 'c' >c
44 $ echo 'c' >c
40 $ hg add c
45 $ hg add c
41 $ hg branch c
46 $ hg branch c
42 marked working directory as branch c
47 marked working directory as branch c
43 $ hg commit -d '5 0' -m "Adding c branch"
48 $ hg commit -d '5 0' -m "Adding c branch"
44
49
45 reserved names
50 reserved names
46
51
47 $ hg branch tip
52 $ hg branch tip
48 abort: the name 'tip' is reserved
53 abort: the name 'tip' is reserved
49 [255]
54 [255]
50 $ hg branch null
55 $ hg branch null
51 abort: the name 'null' is reserved
56 abort: the name 'null' is reserved
52 [255]
57 [255]
53 $ hg branch .
58 $ hg branch .
54 abort: the name '.' is reserved
59 abort: the name '.' is reserved
55 [255]
60 [255]
56
61
57 invalid characters
62 invalid characters
58
63
59 $ hg branch 'foo:bar'
64 $ hg branch 'foo:bar'
60 abort: ':' cannot be used in a name
65 abort: ':' cannot be used in a name
61 [255]
66 [255]
62
67
63 $ hg branch 'foo
68 $ hg branch 'foo
64 > bar'
69 > bar'
65 abort: '\n' cannot be used in a name
70 abort: '\n' cannot be used in a name
66 [255]
71 [255]
67
72
68 trailing or leading spaces should be stripped before testing duplicates
73 trailing or leading spaces should be stripped before testing duplicates
69
74
70 $ hg branch 'b '
75 $ hg branch 'b '
71 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
72 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
73 [255]
78 [255]
74
79
75 $ hg branch ' b'
80 $ hg branch ' b'
76 abort: a branch of the same name already exists
81 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
82 (use 'hg update' to switch to it)
78 [255]
83 [255]
79
84
80 verify update will accept invalid legacy branch names
85 verify update will accept invalid legacy branch names
81
86
82 $ hg init test-invalid-branch-name
87 $ hg init test-invalid-branch-name
83 $ cd test-invalid-branch-name
88 $ cd test-invalid-branch-name
84 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
89 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
85 pulling from *test-invalid-branch-name.hg (glob)
90 pulling from *test-invalid-branch-name.hg (glob)
86 requesting all changes
91 requesting all changes
87 adding changesets
92 adding changesets
88 adding manifests
93 adding manifests
89 adding file changes
94 adding file changes
90 added 3 changesets with 3 changes to 2 files
95 added 3 changesets with 3 changes to 2 files
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92
97
93 $ hg update '"colon:test"'
98 $ hg update '"colon:test"'
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 $ cd ..
100 $ cd ..
96
101
97 $ echo 'd' >d
102 $ echo 'd' >d
98 $ hg add d
103 $ hg add d
99 $ hg branch 'a branch name much longer than the default justification used by branches'
104 $ hg branch 'a branch name much longer than the default justification used by branches'
100 marked working directory as branch a branch name much longer than the default justification used by branches
105 marked working directory as branch a branch name much longer than the default justification used by branches
101 $ hg commit -d '6 0' -m "Adding d branch"
106 $ hg commit -d '6 0' -m "Adding d branch"
102
107
103 $ hg branches
108 $ hg branches
104 a branch name much longer than the default justification used by branches 7:10ff5895aa57
109 a branch name much longer than the default justification used by branches 7:10ff5895aa57
105 b 4:aee39cd168d0
110 b 4:aee39cd168d0
106 c 6:589736a22561 (inactive)
111 c 6:589736a22561 (inactive)
107 a 5:d8cbc61dbaa6 (inactive)
112 a 5:d8cbc61dbaa6 (inactive)
108 default 0:19709c5a4e75 (inactive)
113 default 0:19709c5a4e75 (inactive)
109
114
110 -------
115 -------
111
116
112 $ hg branches -a
117 $ hg branches -a
113 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 a branch name much longer than the default justification used by branches 7:10ff5895aa57
114 b 4:aee39cd168d0
119 b 4:aee39cd168d0
115
120
116 --- Branch a
121 --- Branch a
117
122
118 $ hg log -b a
123 $ hg log -b a
119 changeset: 5:d8cbc61dbaa6
124 changeset: 5:d8cbc61dbaa6
120 branch: a
125 branch: a
121 parent: 2:881fe2b92ad0
126 parent: 2:881fe2b92ad0
122 user: test
127 user: test
123 date: Thu Jan 01 00:00:04 1970 +0000
128 date: Thu Jan 01 00:00:04 1970 +0000
124 summary: Adding b branch head 2
129 summary: Adding b branch head 2
125
130
126 changeset: 2:881fe2b92ad0
131 changeset: 2:881fe2b92ad0
127 branch: a
132 branch: a
128 user: test
133 user: test
129 date: Thu Jan 01 00:00:02 1970 +0000
134 date: Thu Jan 01 00:00:02 1970 +0000
130 summary: Adding to a branch
135 summary: Adding to a branch
131
136
132 changeset: 1:dd6b440dd85a
137 changeset: 1:dd6b440dd85a
133 branch: a
138 branch: a
134 user: test
139 user: test
135 date: Thu Jan 01 00:00:01 1970 +0000
140 date: Thu Jan 01 00:00:01 1970 +0000
136 summary: Adding a branch
141 summary: Adding a branch
137
142
138
143
139 ---- Branch b
144 ---- Branch b
140
145
141 $ hg log -b b
146 $ hg log -b b
142 changeset: 4:aee39cd168d0
147 changeset: 4:aee39cd168d0
143 branch: b
148 branch: b
144 user: test
149 user: test
145 date: Thu Jan 01 00:00:03 1970 +0000
150 date: Thu Jan 01 00:00:03 1970 +0000
146 summary: Adding b branch head 1
151 summary: Adding b branch head 1
147
152
148 changeset: 3:ac22033332d1
153 changeset: 3:ac22033332d1
149 branch: b
154 branch: b
150 parent: 0:19709c5a4e75
155 parent: 0:19709c5a4e75
151 user: test
156 user: test
152 date: Thu Jan 01 00:00:02 1970 +0000
157 date: Thu Jan 01 00:00:02 1970 +0000
153 summary: Adding b branch
158 summary: Adding b branch
154
159
155
160
156 ---- going to test branch closing
161 ---- going to test branch closing
157
162
158 $ hg branches
163 $ hg branches
159 a branch name much longer than the default justification used by branches 7:10ff5895aa57
164 a branch name much longer than the default justification used by branches 7:10ff5895aa57
160 b 4:aee39cd168d0
165 b 4:aee39cd168d0
161 c 6:589736a22561 (inactive)
166 c 6:589736a22561 (inactive)
162 a 5:d8cbc61dbaa6 (inactive)
167 a 5:d8cbc61dbaa6 (inactive)
163 default 0:19709c5a4e75 (inactive)
168 default 0:19709c5a4e75 (inactive)
164 $ hg up -C b
169 $ hg up -C b
165 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
170 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
166 $ echo 'xxx1' >> b
171 $ echo 'xxx1' >> b
167 $ hg commit -d '7 0' -m 'adding cset to branch b'
172 $ hg commit -d '7 0' -m 'adding cset to branch b'
168 $ hg up -C aee39cd168d0
173 $ hg up -C aee39cd168d0
169 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 $ echo 'xxx2' >> b
175 $ echo 'xxx2' >> b
171 $ hg commit -d '8 0' -m 'adding head to branch b'
176 $ hg commit -d '8 0' -m 'adding head to branch b'
172 created new head
177 created new head
173 $ echo 'xxx3' >> b
178 $ echo 'xxx3' >> b
174 $ hg commit -d '9 0' -m 'adding another cset to branch b'
179 $ hg commit -d '9 0' -m 'adding another cset to branch b'
175 $ hg branches
180 $ hg branches
176 b 10:bfbe841b666e
181 b 10:bfbe841b666e
177 a branch name much longer than the default justification used by branches 7:10ff5895aa57
182 a branch name much longer than the default justification used by branches 7:10ff5895aa57
178 c 6:589736a22561 (inactive)
183 c 6:589736a22561 (inactive)
179 a 5:d8cbc61dbaa6 (inactive)
184 a 5:d8cbc61dbaa6 (inactive)
180 default 0:19709c5a4e75 (inactive)
185 default 0:19709c5a4e75 (inactive)
181 $ hg heads --closed
186 $ hg heads --closed
182 changeset: 10:bfbe841b666e
187 changeset: 10:bfbe841b666e
183 branch: b
188 branch: b
184 tag: tip
189 tag: tip
185 user: test
190 user: test
186 date: Thu Jan 01 00:00:09 1970 +0000
191 date: Thu Jan 01 00:00:09 1970 +0000
187 summary: adding another cset to branch b
192 summary: adding another cset to branch b
188
193
189 changeset: 8:eebb944467c9
194 changeset: 8:eebb944467c9
190 branch: b
195 branch: b
191 parent: 4:aee39cd168d0
196 parent: 4:aee39cd168d0
192 user: test
197 user: test
193 date: Thu Jan 01 00:00:07 1970 +0000
198 date: Thu Jan 01 00:00:07 1970 +0000
194 summary: adding cset to branch b
199 summary: adding cset to branch b
195
200
196 changeset: 7:10ff5895aa57
201 changeset: 7:10ff5895aa57
197 branch: a branch name much longer than the default justification used by branches
202 branch: a branch name much longer than the default justification used by branches
198 user: test
203 user: test
199 date: Thu Jan 01 00:00:06 1970 +0000
204 date: Thu Jan 01 00:00:06 1970 +0000
200 summary: Adding d branch
205 summary: Adding d branch
201
206
202 changeset: 6:589736a22561
207 changeset: 6:589736a22561
203 branch: c
208 branch: c
204 user: test
209 user: test
205 date: Thu Jan 01 00:00:05 1970 +0000
210 date: Thu Jan 01 00:00:05 1970 +0000
206 summary: Adding c branch
211 summary: Adding c branch
207
212
208 changeset: 5:d8cbc61dbaa6
213 changeset: 5:d8cbc61dbaa6
209 branch: a
214 branch: a
210 parent: 2:881fe2b92ad0
215 parent: 2:881fe2b92ad0
211 user: test
216 user: test
212 date: Thu Jan 01 00:00:04 1970 +0000
217 date: Thu Jan 01 00:00:04 1970 +0000
213 summary: Adding b branch head 2
218 summary: Adding b branch head 2
214
219
215 changeset: 0:19709c5a4e75
220 changeset: 0:19709c5a4e75
216 user: test
221 user: test
217 date: Thu Jan 01 00:00:00 1970 +0000
222 date: Thu Jan 01 00:00:00 1970 +0000
218 summary: Adding root node
223 summary: Adding root node
219
224
220 $ hg heads
225 $ hg heads
221 changeset: 10:bfbe841b666e
226 changeset: 10:bfbe841b666e
222 branch: b
227 branch: b
223 tag: tip
228 tag: tip
224 user: test
229 user: test
225 date: Thu Jan 01 00:00:09 1970 +0000
230 date: Thu Jan 01 00:00:09 1970 +0000
226 summary: adding another cset to branch b
231 summary: adding another cset to branch b
227
232
228 changeset: 8:eebb944467c9
233 changeset: 8:eebb944467c9
229 branch: b
234 branch: b
230 parent: 4:aee39cd168d0
235 parent: 4:aee39cd168d0
231 user: test
236 user: test
232 date: Thu Jan 01 00:00:07 1970 +0000
237 date: Thu Jan 01 00:00:07 1970 +0000
233 summary: adding cset to branch b
238 summary: adding cset to branch b
234
239
235 changeset: 7:10ff5895aa57
240 changeset: 7:10ff5895aa57
236 branch: a branch name much longer than the default justification used by branches
241 branch: a branch name much longer than the default justification used by branches
237 user: test
242 user: test
238 date: Thu Jan 01 00:00:06 1970 +0000
243 date: Thu Jan 01 00:00:06 1970 +0000
239 summary: Adding d branch
244 summary: Adding d branch
240
245
241 changeset: 6:589736a22561
246 changeset: 6:589736a22561
242 branch: c
247 branch: c
243 user: test
248 user: test
244 date: Thu Jan 01 00:00:05 1970 +0000
249 date: Thu Jan 01 00:00:05 1970 +0000
245 summary: Adding c branch
250 summary: Adding c branch
246
251
247 changeset: 5:d8cbc61dbaa6
252 changeset: 5:d8cbc61dbaa6
248 branch: a
253 branch: a
249 parent: 2:881fe2b92ad0
254 parent: 2:881fe2b92ad0
250 user: test
255 user: test
251 date: Thu Jan 01 00:00:04 1970 +0000
256 date: Thu Jan 01 00:00:04 1970 +0000
252 summary: Adding b branch head 2
257 summary: Adding b branch head 2
253
258
254 changeset: 0:19709c5a4e75
259 changeset: 0:19709c5a4e75
255 user: test
260 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
261 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: Adding root node
262 summary: Adding root node
258
263
259 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
264 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
260 $ hg branches -a
265 $ hg branches -a
261 b 8:eebb944467c9
266 b 8:eebb944467c9
262 a branch name much longer than the default justification used by branches 7:10ff5895aa57
267 a branch name much longer than the default justification used by branches 7:10ff5895aa57
263 $ hg up -C b
268 $ hg up -C b
264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
270 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
266 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
271 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
267 abort: can only close branch heads
272 abort: can only close branch heads
268 [255]
273 [255]
269
274
270 $ hg log -r tip --debug
275 $ hg log -r tip --debug
271 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
276 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
272 branch: b
277 branch: b
273 tag: tip
278 tag: tip
274 phase: draft
279 phase: draft
275 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
280 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
276 parent: -1:0000000000000000000000000000000000000000
281 parent: -1:0000000000000000000000000000000000000000
277 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
282 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
278 user: test
283 user: test
279 date: Thu Jan 01 00:00:09 1970 +0000
284 date: Thu Jan 01 00:00:09 1970 +0000
280 extra: branch=b
285 extra: branch=b
281 extra: close=1
286 extra: close=1
282 description:
287 description:
283 close this part branch too
288 close this part branch too
284
289
285
290
286 --- b branch should be inactive
291 --- b branch should be inactive
287
292
288 $ hg branches
293 $ hg branches
289 a branch name much longer than the default justification used by branches 7:10ff5895aa57
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
290 c 6:589736a22561 (inactive)
295 c 6:589736a22561 (inactive)
291 a 5:d8cbc61dbaa6 (inactive)
296 a 5:d8cbc61dbaa6 (inactive)
292 default 0:19709c5a4e75 (inactive)
297 default 0:19709c5a4e75 (inactive)
293 $ hg branches -c
298 $ hg branches -c
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
299 a branch name much longer than the default justification used by branches 7:10ff5895aa57
295 b 12:e3d49c0575d8 (closed)
300 b 12:e3d49c0575d8 (closed)
296 c 6:589736a22561 (inactive)
301 c 6:589736a22561 (inactive)
297 a 5:d8cbc61dbaa6 (inactive)
302 a 5:d8cbc61dbaa6 (inactive)
298 default 0:19709c5a4e75 (inactive)
303 default 0:19709c5a4e75 (inactive)
299 $ hg branches -a
304 $ hg branches -a
300 a branch name much longer than the default justification used by branches 7:10ff5895aa57
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
301 $ hg branches -q
306 $ hg branches -q
302 a branch name much longer than the default justification used by branches
307 a branch name much longer than the default justification used by branches
303 c
308 c
304 a
309 a
305 default
310 default
306 $ hg heads b
311 $ hg heads b
307 no open branch heads found on branches b
312 no open branch heads found on branches b
308 [1]
313 [1]
309 $ hg heads --closed b
314 $ hg heads --closed b
310 changeset: 12:e3d49c0575d8
315 changeset: 12:e3d49c0575d8
311 branch: b
316 branch: b
312 tag: tip
317 tag: tip
313 parent: 8:eebb944467c9
318 parent: 8:eebb944467c9
314 user: test
319 user: test
315 date: Thu Jan 01 00:00:09 1970 +0000
320 date: Thu Jan 01 00:00:09 1970 +0000
316 summary: close this part branch too
321 summary: close this part branch too
317
322
318 changeset: 11:d3f163457ebf
323 changeset: 11:d3f163457ebf
319 branch: b
324 branch: b
320 user: test
325 user: test
321 date: Thu Jan 01 00:00:09 1970 +0000
326 date: Thu Jan 01 00:00:09 1970 +0000
322 summary: prune bad branch
327 summary: prune bad branch
323
328
324 $ echo 'xxx4' >> b
329 $ echo 'xxx4' >> b
325 $ hg commit -d '9 0' -m 'reopen branch with a change'
330 $ hg commit -d '9 0' -m 'reopen branch with a change'
326 reopening closed branch head 12
331 reopening closed branch head 12
327
332
328 --- branch b is back in action
333 --- branch b is back in action
329
334
330 $ hg branches -a
335 $ hg branches -a
331 b 13:e23b5505d1ad
336 b 13:e23b5505d1ad
332 a branch name much longer than the default justification used by branches 7:10ff5895aa57
337 a branch name much longer than the default justification used by branches 7:10ff5895aa57
333
338
334 ---- test heads listings
339 ---- test heads listings
335
340
336 $ hg heads
341 $ hg heads
337 changeset: 13:e23b5505d1ad
342 changeset: 13:e23b5505d1ad
338 branch: b
343 branch: b
339 tag: tip
344 tag: tip
340 user: test
345 user: test
341 date: Thu Jan 01 00:00:09 1970 +0000
346 date: Thu Jan 01 00:00:09 1970 +0000
342 summary: reopen branch with a change
347 summary: reopen branch with a change
343
348
344 changeset: 7:10ff5895aa57
349 changeset: 7:10ff5895aa57
345 branch: a branch name much longer than the default justification used by branches
350 branch: a branch name much longer than the default justification used by branches
346 user: test
351 user: test
347 date: Thu Jan 01 00:00:06 1970 +0000
352 date: Thu Jan 01 00:00:06 1970 +0000
348 summary: Adding d branch
353 summary: Adding d branch
349
354
350 changeset: 6:589736a22561
355 changeset: 6:589736a22561
351 branch: c
356 branch: c
352 user: test
357 user: test
353 date: Thu Jan 01 00:00:05 1970 +0000
358 date: Thu Jan 01 00:00:05 1970 +0000
354 summary: Adding c branch
359 summary: Adding c branch
355
360
356 changeset: 5:d8cbc61dbaa6
361 changeset: 5:d8cbc61dbaa6
357 branch: a
362 branch: a
358 parent: 2:881fe2b92ad0
363 parent: 2:881fe2b92ad0
359 user: test
364 user: test
360 date: Thu Jan 01 00:00:04 1970 +0000
365 date: Thu Jan 01 00:00:04 1970 +0000
361 summary: Adding b branch head 2
366 summary: Adding b branch head 2
362
367
363 changeset: 0:19709c5a4e75
368 changeset: 0:19709c5a4e75
364 user: test
369 user: test
365 date: Thu Jan 01 00:00:00 1970 +0000
370 date: Thu Jan 01 00:00:00 1970 +0000
366 summary: Adding root node
371 summary: Adding root node
367
372
368
373
369 branch default
374 branch default
370
375
371 $ hg heads default
376 $ hg heads default
372 changeset: 0:19709c5a4e75
377 changeset: 0:19709c5a4e75
373 user: test
378 user: test
374 date: Thu Jan 01 00:00:00 1970 +0000
379 date: Thu Jan 01 00:00:00 1970 +0000
375 summary: Adding root node
380 summary: Adding root node
376
381
377
382
378 branch a
383 branch a
379
384
380 $ hg heads a
385 $ hg heads a
381 changeset: 5:d8cbc61dbaa6
386 changeset: 5:d8cbc61dbaa6
382 branch: a
387 branch: a
383 parent: 2:881fe2b92ad0
388 parent: 2:881fe2b92ad0
384 user: test
389 user: test
385 date: Thu Jan 01 00:00:04 1970 +0000
390 date: Thu Jan 01 00:00:04 1970 +0000
386 summary: Adding b branch head 2
391 summary: Adding b branch head 2
387
392
388 $ hg heads --active a
393 $ hg heads --active a
389 no open branch heads found on branches a
394 no open branch heads found on branches a
390 [1]
395 [1]
391
396
392 branch b
397 branch b
393
398
394 $ hg heads b
399 $ hg heads b
395 changeset: 13:e23b5505d1ad
400 changeset: 13:e23b5505d1ad
396 branch: b
401 branch: b
397 tag: tip
402 tag: tip
398 user: test
403 user: test
399 date: Thu Jan 01 00:00:09 1970 +0000
404 date: Thu Jan 01 00:00:09 1970 +0000
400 summary: reopen branch with a change
405 summary: reopen branch with a change
401
406
402 $ hg heads --closed b
407 $ hg heads --closed b
403 changeset: 13:e23b5505d1ad
408 changeset: 13:e23b5505d1ad
404 branch: b
409 branch: b
405 tag: tip
410 tag: tip
406 user: test
411 user: test
407 date: Thu Jan 01 00:00:09 1970 +0000
412 date: Thu Jan 01 00:00:09 1970 +0000
408 summary: reopen branch with a change
413 summary: reopen branch with a change
409
414
410 changeset: 11:d3f163457ebf
415 changeset: 11:d3f163457ebf
411 branch: b
416 branch: b
412 user: test
417 user: test
413 date: Thu Jan 01 00:00:09 1970 +0000
418 date: Thu Jan 01 00:00:09 1970 +0000
414 summary: prune bad branch
419 summary: prune bad branch
415
420
416 default branch colors:
421 default branch colors:
417
422
418 $ cat <<EOF >> $HGRCPATH
423 $ cat <<EOF >> $HGRCPATH
419 > [extensions]
424 > [extensions]
420 > color =
425 > color =
421 > [color]
426 > [color]
422 > mode = ansi
427 > mode = ansi
423 > EOF
428 > EOF
424
429
425 $ hg up -C c
430 $ hg up -C c
426 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
431 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
427 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
432 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
428 $ hg up -C b
433 $ hg up -C b
429 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
434 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
430 $ hg branches --color=always
435 $ hg branches --color=always
431 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
436 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
432 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
437 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
433 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
438 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
434 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
439 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
435
440
436 default closed branch color:
441 default closed branch color:
437
442
438 $ hg branches --color=always --closed
443 $ hg branches --color=always --closed
439 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
444 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
440 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
445 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
441 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
446 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
442 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
447 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
443 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
448 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
444
449
445 $ cat <<EOF >> $HGRCPATH
450 $ cat <<EOF >> $HGRCPATH
446 > [extensions]
451 > [extensions]
447 > color =
452 > color =
448 > [color]
453 > [color]
449 > branches.active = green
454 > branches.active = green
450 > branches.closed = blue
455 > branches.closed = blue
451 > branches.current = red
456 > branches.current = red
452 > branches.inactive = magenta
457 > branches.inactive = magenta
453 > log.changeset = cyan
458 > log.changeset = cyan
454 > EOF
459 > EOF
455
460
456 custom branch colors:
461 custom branch colors:
457
462
458 $ hg branches --color=always
463 $ hg branches --color=always
459 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
464 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
460 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
465 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
461 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
466 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
462 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
467 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
463
468
464 custom closed branch color:
469 custom closed branch color:
465
470
466 $ hg branches --color=always --closed
471 $ hg branches --color=always --closed
467 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
472 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
468 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
473 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
469 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
474 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
470 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
475 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
471 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
476 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
472
477
473 template output:
478 template output:
474
479
475 $ hg branches -Tjson --closed
480 $ hg branches -Tjson --closed
476 [
481 [
477 {
482 {
478 "active": true,
483 "active": true,
479 "branch": "b",
484 "branch": "b",
480 "closed": false,
485 "closed": false,
481 "current": true,
486 "current": true,
482 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
487 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
483 "rev": 13
488 "rev": 13
484 },
489 },
485 {
490 {
486 "active": true,
491 "active": true,
487 "branch": "a branch name much longer than the default justification used by branches",
492 "branch": "a branch name much longer than the default justification used by branches",
488 "closed": false,
493 "closed": false,
489 "current": false,
494 "current": false,
490 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
495 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
491 "rev": 7
496 "rev": 7
492 },
497 },
493 {
498 {
494 "active": false,
499 "active": false,
495 "branch": "c",
500 "branch": "c",
496 "closed": true,
501 "closed": true,
497 "current": false,
502 "current": false,
498 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
503 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
499 "rev": 14
504 "rev": 14
500 },
505 },
501 {
506 {
502 "active": false,
507 "active": false,
503 "branch": "a",
508 "branch": "a",
504 "closed": false,
509 "closed": false,
505 "current": false,
510 "current": false,
506 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
511 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
507 "rev": 5
512 "rev": 5
508 },
513 },
509 {
514 {
510 "active": false,
515 "active": false,
511 "branch": "default",
516 "branch": "default",
512 "closed": false,
517 "closed": false,
513 "current": false,
518 "current": false,
514 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
519 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
515 "rev": 0
520 "rev": 0
516 }
521 }
517 ]
522 ]
518
523
519 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
524 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
520 c
525 c
521
526
522 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
527 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
523 b: reopen branch with a change
528 b: reopen branch with a change
524 a: Adding d branch
529 a: Adding d branch
525 a: Adding b branch head 2
530 a: Adding b branch head 2
526 default: Adding root node
531 default: Adding root node
527
532
528 Tests of revision branch name caching
533 Tests of revision branch name caching
529
534
530 We rev branch cache is updated automatically. In these tests we use a trick to
535 We rev branch cache is updated automatically. In these tests we use a trick to
531 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
536 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
532 rebuild that also will populate the rev branch cache.
537 rebuild that also will populate the rev branch cache.
533
538
534 revision branch cache is created when building the branch head cache
539 revision branch cache is created when building the branch head cache
535 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
540 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
536 5
541 5
537 $ f --hexdump --size .hg/cache/rbc-*
542 $ f --hexdump --size .hg/cache/rbc-*
538 .hg/cache/rbc-names-v1: size=87
543 .hg/cache/rbc-names-v1: size=87
539 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
544 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
540 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
545 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
541 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
546 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
542 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
547 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
543 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
548 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
544 0050: 72 61 6e 63 68 65 73 |ranches|
549 0050: 72 61 6e 63 68 65 73 |ranches|
545 .hg/cache/rbc-revs-v1: size=120
550 .hg/cache/rbc-revs-v1: size=120
546 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
551 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
547 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
552 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
548 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
553 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
549 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
554 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
550 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
555 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
551 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
556 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
552 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
557 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
553 0070: f8 94 c2 56 80 00 00 03 |...V....|
558 0070: f8 94 c2 56 80 00 00 03 |...V....|
554
559
555 no errors when revbranchcache is not writable
560 no errors when revbranchcache is not writable
556
561
557 $ echo >> .hg/cache/rbc-revs-v1
562 $ echo >> .hg/cache/rbc-revs-v1
558 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
563 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
559 $ mkdir .hg/cache/rbc-revs-v1
564 $ mkdir .hg/cache/rbc-revs-v1
560 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
565 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
561 5
566 5
562 $ rmdir .hg/cache/rbc-revs-v1
567 $ rmdir .hg/cache/rbc-revs-v1
563 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
568 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
564
569
565 no errors when wlock cannot be acquired
570 no errors when wlock cannot be acquired
566
571
567 #if unix-permissions
572 #if unix-permissions
568 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
573 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
569 $ rm -f .hg/cache/branch*
574 $ rm -f .hg/cache/branch*
570 $ chmod 555 .hg
575 $ chmod 555 .hg
571 $ hg head a -T '{rev}\n'
576 $ hg head a -T '{rev}\n'
572 5
577 5
573 $ chmod 755 .hg
578 $ chmod 755 .hg
574 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
579 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
575 #endif
580 #endif
576
581
577 recovery from invalid cache revs file with trailing data
582 recovery from invalid cache revs file with trailing data
578 $ echo >> .hg/cache/rbc-revs-v1
583 $ echo >> .hg/cache/rbc-revs-v1
579 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
584 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
580 5
585 5
581 truncating cache/rbc-revs-v1 to 120
586 truncating cache/rbc-revs-v1 to 120
582 $ f --size .hg/cache/rbc-revs*
587 $ f --size .hg/cache/rbc-revs*
583 .hg/cache/rbc-revs-v1: size=120
588 .hg/cache/rbc-revs-v1: size=120
584 recovery from invalid cache file with partial last record
589 recovery from invalid cache file with partial last record
585 $ mv .hg/cache/rbc-revs-v1 .
590 $ mv .hg/cache/rbc-revs-v1 .
586 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
591 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
587 $ f --size .hg/cache/rbc-revs*
592 $ f --size .hg/cache/rbc-revs*
588 .hg/cache/rbc-revs-v1: size=119
593 .hg/cache/rbc-revs-v1: size=119
589 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
594 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
590 5
595 5
591 truncating cache/rbc-revs-v1 to 112
596 truncating cache/rbc-revs-v1 to 112
592 $ f --size .hg/cache/rbc-revs*
597 $ f --size .hg/cache/rbc-revs*
593 .hg/cache/rbc-revs-v1: size=120
598 .hg/cache/rbc-revs-v1: size=120
594 recovery from invalid cache file with missing record - no truncation
599 recovery from invalid cache file with missing record - no truncation
595 $ mv .hg/cache/rbc-revs-v1 .
600 $ mv .hg/cache/rbc-revs-v1 .
596 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
601 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
597 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
602 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
598 5
603 5
599 $ f --size .hg/cache/rbc-revs*
604 $ f --size .hg/cache/rbc-revs*
600 .hg/cache/rbc-revs-v1: size=120
605 .hg/cache/rbc-revs-v1: size=120
601 recovery from invalid cache file with some bad records
606 recovery from invalid cache file with some bad records
602 $ mv .hg/cache/rbc-revs-v1 .
607 $ mv .hg/cache/rbc-revs-v1 .
603 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
608 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
604 $ f --size .hg/cache/rbc-revs*
609 $ f --size .hg/cache/rbc-revs*
605 .hg/cache/rbc-revs-v1: size=8
610 .hg/cache/rbc-revs-v1: size=8
606 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
611 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
607 $ f --size .hg/cache/rbc-revs*
612 $ f --size .hg/cache/rbc-revs*
608 .hg/cache/rbc-revs-v1: size=120
613 .hg/cache/rbc-revs-v1: size=120
609 $ hg log -r 'branch(.)' -T '{rev} ' --debug
614 $ hg log -r 'branch(.)' -T '{rev} ' --debug
610 history modification detected - truncating revision branch cache to revision 13
615 history modification detected - truncating revision branch cache to revision 13
611 history modification detected - truncating revision branch cache to revision 1
616 history modification detected - truncating revision branch cache to revision 1
612 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
617 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
613 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
618 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
614 5
619 5
615 truncating cache/rbc-revs-v1 to 104
620 truncating cache/rbc-revs-v1 to 104
616 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
621 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
617 .hg/cache/rbc-revs-v1: size=120
622 .hg/cache/rbc-revs-v1: size=120
618 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
623 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
619 cache is updated when committing
624 cache is updated when committing
620 $ hg branch i-will-regret-this
625 $ hg branch i-will-regret-this
621 marked working directory as branch i-will-regret-this
626 marked working directory as branch i-will-regret-this
622 $ hg ci -m regrets
627 $ hg ci -m regrets
623 $ f --size .hg/cache/rbc-*
628 $ f --size .hg/cache/rbc-*
624 .hg/cache/rbc-names-v1: size=106
629 .hg/cache/rbc-names-v1: size=106
625 .hg/cache/rbc-revs-v1: size=128
630 .hg/cache/rbc-revs-v1: size=128
626 update after rollback - the cache will be correct but rbc-names will will still
631 update after rollback - the cache will be correct but rbc-names will will still
627 contain the branch name even though it no longer is used
632 contain the branch name even though it no longer is used
628 $ hg up -qr '.^'
633 $ hg up -qr '.^'
629 $ hg rollback -qf
634 $ hg rollback -qf
630 $ f --size --hexdump .hg/cache/rbc-*
635 $ f --size --hexdump .hg/cache/rbc-*
631 .hg/cache/rbc-names-v1: size=106
636 .hg/cache/rbc-names-v1: size=106
632 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
637 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
633 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
638 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
634 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
639 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
635 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
640 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
636 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
641 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
637 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
642 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
638 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
643 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
639 .hg/cache/rbc-revs-v1: size=120
644 .hg/cache/rbc-revs-v1: size=120
640 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
645 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
641 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
646 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
642 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
647 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
643 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
648 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
644 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
649 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
645 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
650 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
646 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
651 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
647 0070: f8 94 c2 56 80 00 00 03 |...V....|
652 0070: f8 94 c2 56 80 00 00 03 |...V....|
648 cache is updated/truncated when stripping - it is thus very hard to get in a
653 cache is updated/truncated when stripping - it is thus very hard to get in a
649 situation where the cache is out of sync and the hash check detects it
654 situation where the cache is out of sync and the hash check detects it
650 $ hg --config extensions.strip= strip -r tip --nob
655 $ hg --config extensions.strip= strip -r tip --nob
651 $ f --size .hg/cache/rbc-revs*
656 $ f --size .hg/cache/rbc-revs*
652 .hg/cache/rbc-revs-v1: size=112
657 .hg/cache/rbc-revs-v1: size=112
653
658
654 cache is rebuilt when corruption is detected
659 cache is rebuilt when corruption is detected
655 $ echo > .hg/cache/rbc-names-v1
660 $ echo > .hg/cache/rbc-names-v1
656 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
661 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
657 referenced branch names not found - rebuilding revision branch cache from scratch
662 referenced branch names not found - rebuilding revision branch cache from scratch
658 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
663 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
659 $ f --size --hexdump .hg/cache/rbc-*
664 $ f --size --hexdump .hg/cache/rbc-*
660 .hg/cache/rbc-names-v1: size=79
665 .hg/cache/rbc-names-v1: size=79
661 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
666 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
662 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
667 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
663 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
668 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
664 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
669 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
665 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
670 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
666 .hg/cache/rbc-revs-v1: size=112
671 .hg/cache/rbc-revs-v1: size=112
667 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
672 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
668 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
673 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
669 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
674 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
670 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
675 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
671 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
676 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
672 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
677 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
673 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
678 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
674
679
675 Test that cache files are created and grows correctly:
680 Test that cache files are created and grows correctly:
676
681
677 $ rm .hg/cache/rbc*
682 $ rm .hg/cache/rbc*
678 $ hg log -r "5 & branch(5)" -T "{rev}\n"
683 $ hg log -r "5 & branch(5)" -T "{rev}\n"
679 5
684 5
680 $ f --size --hexdump .hg/cache/rbc-*
685 $ f --size --hexdump .hg/cache/rbc-*
681 .hg/cache/rbc-names-v1: size=1
686 .hg/cache/rbc-names-v1: size=1
682 0000: 61 |a|
687 0000: 61 |a|
683 .hg/cache/rbc-revs-v1: size=112
688 .hg/cache/rbc-revs-v1: size=112
684 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
689 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
685 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
690 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
686 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
691 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
687 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
692 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
688 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
693 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
689 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
694 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
690 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
695 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
691
696
692 $ cd ..
697 $ cd ..
693
698
694 Test for multiple incorrect branch cache entries:
699 Test for multiple incorrect branch cache entries:
695
700
696 $ hg init b
701 $ hg init b
697 $ cd b
702 $ cd b
698 $ touch f
703 $ touch f
699 $ hg ci -Aqmf
704 $ hg ci -Aqmf
700 $ echo >> f
705 $ echo >> f
701 $ hg ci -Amf
706 $ hg ci -Amf
702 $ hg branch -q branch
707 $ hg branch -q branch
703 $ hg ci -Amf
708 $ hg ci -Amf
704
709
705 $ f --size --hexdump .hg/cache/rbc-*
710 $ f --size --hexdump .hg/cache/rbc-*
706 .hg/cache/rbc-names-v1: size=14
711 .hg/cache/rbc-names-v1: size=14
707 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
712 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
708 .hg/cache/rbc-revs-v1: size=24
713 .hg/cache/rbc-revs-v1: size=24
709 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
714 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
710 0010: 56 46 78 69 00 00 00 01 |VFxi....|
715 0010: 56 46 78 69 00 00 00 01 |VFxi....|
711 $ : > .hg/cache/rbc-revs-v1
716 $ : > .hg/cache/rbc-revs-v1
712
717
713 No superfluous rebuilding of cache:
718 No superfluous rebuilding of cache:
714 $ hg log -r "branch(null)&branch(branch)" --debug
719 $ hg log -r "branch(null)&branch(branch)" --debug
715 $ f --size --hexdump .hg/cache/rbc-*
720 $ f --size --hexdump .hg/cache/rbc-*
716 .hg/cache/rbc-names-v1: size=14
721 .hg/cache/rbc-names-v1: size=14
717 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
722 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
718 .hg/cache/rbc-revs-v1: size=24
723 .hg/cache/rbc-revs-v1: size=24
719 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
724 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
720 0010: 56 46 78 69 00 00 00 01 |VFxi....|
725 0010: 56 46 78 69 00 00 00 01 |VFxi....|
721
726
722 $ cd ..
727 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now