##// END OF EJS Templates
branchcache: add a "pure topological head" fast path...
marmoute -
r52429:718f28ea default
parent child Browse files
Show More
@@ -1,1299 +1,1394 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 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@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
8
9 import struct
9 import struct
10
10
11 from .node import (
11 from .node import (
12 bin,
12 bin,
13 hex,
13 hex,
14 nullrev,
14 nullrev,
15 )
15 )
16
16
17 from typing import (
17 from typing import (
18 Any,
18 Any,
19 Callable,
19 Callable,
20 Dict,
20 Dict,
21 Iterable,
21 Iterable,
22 List,
22 List,
23 Optional,
23 Optional,
24 Set,
24 Set,
25 TYPE_CHECKING,
25 TYPE_CHECKING,
26 Tuple,
26 Tuple,
27 Union,
27 Union,
28 cast,
28 cast,
29 )
29 )
30
30
31 from . import (
31 from . import (
32 encoding,
32 encoding,
33 error,
33 error,
34 obsolete,
34 obsolete,
35 scmutil,
35 scmutil,
36 util,
36 util,
37 )
37 )
38
38
39 from .utils import (
39 from .utils import (
40 repoviewutil,
40 repoviewutil,
41 stringutil,
41 stringutil,
42 )
42 )
43
43
44 if TYPE_CHECKING:
44 if TYPE_CHECKING:
45 from . import localrepo
45 from . import localrepo
46
46
47 assert [localrepo]
47 assert [localrepo]
48
48
49 subsettable = repoviewutil.subsettable
49 subsettable = repoviewutil.subsettable
50
50
51 calcsize = struct.calcsize
51 calcsize = struct.calcsize
52 pack_into = struct.pack_into
52 pack_into = struct.pack_into
53 unpack_from = struct.unpack_from
53 unpack_from = struct.unpack_from
54
54
55
55
56 class BranchMapCache:
56 class BranchMapCache:
57 """mapping of filtered views of repo with their branchcache"""
57 """mapping of filtered views of repo with their branchcache"""
58
58
59 def __init__(self):
59 def __init__(self):
60 self._per_filter = {}
60 self._per_filter = {}
61
61
62 def __getitem__(self, repo):
62 def __getitem__(self, repo):
63 self.updatecache(repo)
63 self.updatecache(repo)
64 bcache = self._per_filter[repo.filtername]
64 bcache = self._per_filter[repo.filtername]
65 bcache._ensure_populated(repo)
65 assert bcache._filtername == repo.filtername, (
66 assert bcache._filtername == repo.filtername, (
66 bcache._filtername,
67 bcache._filtername,
67 repo.filtername,
68 repo.filtername,
68 )
69 )
69 return bcache
70 return bcache
70
71
71 def update_disk(self, repo):
72 def update_disk(self, repo):
72 """ensure and up-to-date cache is (or will be) written on disk
73 """ensure and up-to-date cache is (or will be) written on disk
73
74
74 The cache for this repository view is updated if needed and written on
75 The cache for this repository view is updated if needed and written on
75 disk.
76 disk.
76
77
77 If a transaction is in progress, the writing is schedule to transaction
78 If a transaction is in progress, the writing is schedule to transaction
78 close. See the `BranchMapCache.write_dirty` method.
79 close. See the `BranchMapCache.write_dirty` method.
79
80
80 This method exist independently of __getitem__ as it is sometime useful
81 This method exist independently of __getitem__ as it is sometime useful
81 to signal that we have no intend to use the data in memory yet.
82 to signal that we have no intend to use the data in memory yet.
82 """
83 """
83 self.updatecache(repo)
84 self.updatecache(repo)
84 bcache = self._per_filter[repo.filtername]
85 bcache = self._per_filter[repo.filtername]
85 assert bcache._filtername == repo.filtername, (
86 assert bcache._filtername == repo.filtername, (
86 bcache._filtername,
87 bcache._filtername,
87 repo.filtername,
88 repo.filtername,
88 )
89 )
89 tr = repo.currenttransaction()
90 tr = repo.currenttransaction()
90 if getattr(tr, 'finalized', True):
91 if getattr(tr, 'finalized', True):
91 bcache.sync_disk(repo)
92 bcache.sync_disk(repo)
92
93
93 def updatecache(self, repo):
94 def updatecache(self, repo):
94 """Update the cache for the given filtered view on a repository"""
95 """Update the cache for the given filtered view on a repository"""
95 # This can trigger updates for the caches for subsets of the filtered
96 # This can trigger updates for the caches for subsets of the filtered
96 # view, e.g. when there is no cache for this filtered view or the cache
97 # view, e.g. when there is no cache for this filtered view or the cache
97 # is stale.
98 # is stale.
98
99
99 cl = repo.changelog
100 cl = repo.changelog
100 filtername = repo.filtername
101 filtername = repo.filtername
101 bcache = self._per_filter.get(filtername)
102 bcache = self._per_filter.get(filtername)
102 if bcache is None or not bcache.validfor(repo):
103 if bcache is None or not bcache.validfor(repo):
103 # cache object missing or cache object stale? Read from disk
104 # cache object missing or cache object stale? Read from disk
104 bcache = branch_cache_from_file(repo)
105 bcache = branch_cache_from_file(repo)
105
106
106 revs = []
107 revs = []
107 if bcache is None:
108 if bcache is None:
108 # no (fresh) cache available anymore, perhaps we can re-use
109 # no (fresh) cache available anymore, perhaps we can re-use
109 # the cache for a subset, then extend that to add info on missing
110 # the cache for a subset, then extend that to add info on missing
110 # revisions.
111 # revisions.
111 subsetname = subsettable.get(filtername)
112 subsetname = subsettable.get(filtername)
112 if subsetname is not None:
113 if subsetname is not None:
113 subset = repo.filtered(subsetname)
114 subset = repo.filtered(subsetname)
114 self.updatecache(subset)
115 self.updatecache(subset)
115 bcache = self._per_filter[subset.filtername].inherit_for(repo)
116 bcache = self._per_filter[subset.filtername].inherit_for(repo)
116 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
117 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
117 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
118 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
118 else:
119 else:
119 # nothing to fall back on, start empty.
120 # nothing to fall back on, start empty.
120 bcache = new_branch_cache(repo)
121 bcache = new_branch_cache(repo)
121
122
122 revs.extend(cl.revs(start=bcache.tiprev + 1))
123 revs.extend(cl.revs(start=bcache.tiprev + 1))
123 if revs:
124 if revs:
124 bcache.update(repo, revs)
125 bcache.update(repo, revs)
125
126
126 assert bcache.validfor(repo), filtername
127 assert bcache.validfor(repo), filtername
127 self._per_filter[repo.filtername] = bcache
128 self._per_filter[repo.filtername] = bcache
128
129
129 def replace(self, repo, remotebranchmap):
130 def replace(self, repo, remotebranchmap):
130 """Replace the branchmap cache for a repo with a branch mapping.
131 """Replace the branchmap cache for a repo with a branch mapping.
131
132
132 This is likely only called during clone with a branch map from a
133 This is likely only called during clone with a branch map from a
133 remote.
134 remote.
134
135
135 """
136 """
136 cl = repo.changelog
137 cl = repo.changelog
137 clrev = cl.rev
138 clrev = cl.rev
138 clbranchinfo = cl.branchinfo
139 clbranchinfo = cl.branchinfo
139 rbheads = []
140 rbheads = []
140 closed = set()
141 closed = set()
141 for bheads in remotebranchmap.values():
142 for bheads in remotebranchmap.values():
142 rbheads += bheads
143 rbheads += bheads
143 for h in bheads:
144 for h in bheads:
144 r = clrev(h)
145 r = clrev(h)
145 b, c = clbranchinfo(r)
146 b, c = clbranchinfo(r)
146 if c:
147 if c:
147 closed.add(h)
148 closed.add(h)
148
149
149 if rbheads:
150 if rbheads:
150 rtiprev = max((int(clrev(node)) for node in rbheads))
151 rtiprev = max((int(clrev(node)) for node in rbheads))
151 cache = new_branch_cache(
152 cache = new_branch_cache(
152 repo,
153 repo,
153 remotebranchmap,
154 remotebranchmap,
154 repo[rtiprev].node(),
155 repo[rtiprev].node(),
155 rtiprev,
156 rtiprev,
156 closednodes=closed,
157 closednodes=closed,
157 )
158 )
158
159
159 # Try to stick it as low as possible
160 # Try to stick it as low as possible
160 # filter above served are unlikely to be fetch from a clone
161 # filter above served are unlikely to be fetch from a clone
161 for candidate in (b'base', b'immutable', b'served'):
162 for candidate in (b'base', b'immutable', b'served'):
162 rview = repo.filtered(candidate)
163 rview = repo.filtered(candidate)
163 if cache.validfor(rview):
164 if cache.validfor(rview):
164 cache._filtername = candidate
165 cache._filtername = candidate
165 self._per_filter[candidate] = cache
166 self._per_filter[candidate] = cache
166 cache._state = STATE_DIRTY
167 cache._state = STATE_DIRTY
167 cache.write(rview)
168 cache.write(rview)
168 return
169 return
169
170
170 def clear(self):
171 def clear(self):
171 self._per_filter.clear()
172 self._per_filter.clear()
172
173
173 def write_dirty(self, repo):
174 def write_dirty(self, repo):
174 unfi = repo.unfiltered()
175 unfi = repo.unfiltered()
175 for filtername in repoviewutil.get_ordered_subset():
176 for filtername in repoviewutil.get_ordered_subset():
176 cache = self._per_filter.get(filtername)
177 cache = self._per_filter.get(filtername)
177 if cache is None:
178 if cache is None:
178 continue
179 continue
179 if filtername is None:
180 if filtername is None:
180 repo = unfi
181 repo = unfi
181 else:
182 else:
182 repo = unfi.filtered(filtername)
183 repo = unfi.filtered(filtername)
183 cache.sync_disk(repo)
184 cache.sync_disk(repo)
184
185
185
186
186 def _unknownnode(node):
187 def _unknownnode(node):
187 """raises ValueError when branchcache found a node which does not exists"""
188 """raises ValueError when branchcache found a node which does not exists"""
188 raise ValueError('node %s does not exist' % node.hex())
189 raise ValueError('node %s does not exist' % node.hex())
189
190
190
191
191 def _branchcachedesc(repo):
192 def _branchcachedesc(repo):
192 if repo.filtername is not None:
193 if repo.filtername is not None:
193 return b'branch cache (%s)' % repo.filtername
194 return b'branch cache (%s)' % repo.filtername
194 else:
195 else:
195 return b'branch cache'
196 return b'branch cache'
196
197
197
198
198 class _BaseBranchCache:
199 class _BaseBranchCache:
199 """A dict like object that hold branches heads cache.
200 """A dict like object that hold branches heads cache.
200
201
201 This cache is used to avoid costly computations to determine all the
202 This cache is used to avoid costly computations to determine all the
202 branch heads of a repo.
203 branch heads of a repo.
203 """
204 """
204
205
205 def __init__(
206 def __init__(
206 self,
207 self,
207 repo: "localrepo.localrepository",
208 repo: "localrepo.localrepository",
208 entries: Union[
209 entries: Union[
209 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
210 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
210 ] = (),
211 ] = (),
211 closed_nodes: Optional[Set[bytes]] = None,
212 closed_nodes: Optional[Set[bytes]] = None,
212 ) -> None:
213 ) -> None:
213 """hasnode is a function which can be used to verify whether changelog
214 """hasnode is a function which can be used to verify whether changelog
214 has a given node or not. If it's not provided, we assume that every node
215 has a given node or not. If it's not provided, we assume that every node
215 we have exists in changelog"""
216 we have exists in changelog"""
216 # closednodes is a set of nodes that close their branch. If the branch
217 # closednodes is a set of nodes that close their branch. If the branch
217 # cache has been updated, it may contain nodes that are no longer
218 # cache has been updated, it may contain nodes that are no longer
218 # heads.
219 # heads.
219 if closed_nodes is None:
220 if closed_nodes is None:
220 closed_nodes = set()
221 closed_nodes = set()
221 self._closednodes = set(closed_nodes)
222 self._closednodes = set(closed_nodes)
222 self._entries = dict(entries)
223 self._entries = dict(entries)
223
224
224 def __iter__(self):
225 def __iter__(self):
225 return iter(self._entries)
226 return iter(self._entries)
226
227
227 def __setitem__(self, key, value):
228 def __setitem__(self, key, value):
228 self._entries[key] = value
229 self._entries[key] = value
229
230
230 def __getitem__(self, key):
231 def __getitem__(self, key):
231 return self._entries[key]
232 return self._entries[key]
232
233
233 def __contains__(self, key):
234 def __contains__(self, key):
234 return key in self._entries
235 return key in self._entries
235
236
236 def iteritems(self):
237 def iteritems(self):
237 return self._entries.items()
238 return self._entries.items()
238
239
239 items = iteritems
240 items = iteritems
240
241
241 def hasbranch(self, label):
242 def hasbranch(self, label):
242 """checks whether a branch of this name exists or not"""
243 """checks whether a branch of this name exists or not"""
243 return label in self._entries
244 return label in self._entries
244
245
245 def _branchtip(self, heads):
246 def _branchtip(self, heads):
246 """Return tuple with last open head in heads and false,
247 """Return tuple with last open head in heads and false,
247 otherwise return last closed head and true."""
248 otherwise return last closed head and true."""
248 tip = heads[-1]
249 tip = heads[-1]
249 closed = True
250 closed = True
250 for h in reversed(heads):
251 for h in reversed(heads):
251 if h not in self._closednodes:
252 if h not in self._closednodes:
252 tip = h
253 tip = h
253 closed = False
254 closed = False
254 break
255 break
255 return tip, closed
256 return tip, closed
256
257
257 def branchtip(self, branch):
258 def branchtip(self, branch):
258 """Return the tipmost open head on branch head, otherwise return the
259 """Return the tipmost open head on branch head, otherwise return the
259 tipmost closed head on branch.
260 tipmost closed head on branch.
260 Raise KeyError for unknown branch."""
261 Raise KeyError for unknown branch."""
261 return self._branchtip(self[branch])[0]
262 return self._branchtip(self[branch])[0]
262
263
263 def iteropen(self, nodes):
264 def iteropen(self, nodes):
264 return (n for n in nodes if n not in self._closednodes)
265 return (n for n in nodes if n not in self._closednodes)
265
266
266 def branchheads(self, branch, closed=False):
267 def branchheads(self, branch, closed=False):
267 heads = self._entries[branch]
268 heads = self._entries[branch]
268 if not closed:
269 if not closed:
269 heads = list(self.iteropen(heads))
270 heads = list(self.iteropen(heads))
270 return heads
271 return heads
271
272
272 def iterbranches(self):
273 def iterbranches(self):
273 for bn, heads in self.items():
274 for bn, heads in self.items():
274 yield (bn, heads) + self._branchtip(heads)
275 yield (bn, heads) + self._branchtip(heads)
275
276
276 def iterheads(self):
277 def iterheads(self):
277 """returns all the heads"""
278 """returns all the heads"""
278 return self._entries.values()
279 return self._entries.values()
279
280
280 def update(self, repo, revgen):
281 def update(self, repo, revgen):
281 """Given a branchhead cache, self, that may have extra nodes or be
282 """Given a branchhead cache, self, that may have extra nodes or be
282 missing heads, and a generator of nodes that are strictly a superset of
283 missing heads, and a generator of nodes that are strictly a superset of
283 heads missing, this function updates self to be correct.
284 heads missing, this function updates self to be correct.
284 """
285 """
285 starttime = util.timer()
286 starttime = util.timer()
286 cl = repo.changelog
287 cl = repo.changelog
287 # Faster than using ctx.obsolete()
288 # Faster than using ctx.obsolete()
288 obsrevs = obsolete.getrevs(repo, b'obsolete')
289 obsrevs = obsolete.getrevs(repo, b'obsolete')
289 # collect new branch entries
290 # collect new branch entries
290 newbranches = {}
291 newbranches = {}
291 new_closed = set()
292 new_closed = set()
292 obs_ignored = set()
293 obs_ignored = set()
293 getbranchinfo = repo.revbranchcache().branchinfo
294 getbranchinfo = repo.revbranchcache().branchinfo
294 max_rev = -1
295 max_rev = -1
295 for r in revgen:
296 for r in revgen:
296 max_rev = max(max_rev, r)
297 max_rev = max(max_rev, r)
297 if r in obsrevs:
298 if r in obsrevs:
298 # We ignore obsolete changesets as they shouldn't be
299 # We ignore obsolete changesets as they shouldn't be
299 # considered heads.
300 # considered heads.
300 obs_ignored.add(r)
301 obs_ignored.add(r)
301 continue
302 continue
302 branch, closesbranch = getbranchinfo(r)
303 branch, closesbranch = getbranchinfo(r)
303 newbranches.setdefault(branch, []).append(r)
304 newbranches.setdefault(branch, []).append(r)
304 if closesbranch:
305 if closesbranch:
305 new_closed.add(r)
306 new_closed.add(r)
306 if max_rev < 0:
307 if max_rev < 0:
307 msg = "running branchcache.update without revision to update"
308 msg = "running branchcache.update without revision to update"
308 raise error.ProgrammingError(msg)
309 raise error.ProgrammingError(msg)
309
310
310 self._process_new(
311 self._process_new(
311 repo,
312 repo,
312 newbranches,
313 newbranches,
313 new_closed,
314 new_closed,
314 obs_ignored,
315 obs_ignored,
315 max_rev,
316 max_rev,
316 )
317 )
317
318
318 self._closednodes.update(cl.node(rev) for rev in new_closed)
319 self._closednodes.update(cl.node(rev) for rev in new_closed)
319
320
320 duration = util.timer() - starttime
321 duration = util.timer() - starttime
321 repo.ui.log(
322 repo.ui.log(
322 b'branchcache',
323 b'branchcache',
323 b'updated %s in %.4f seconds\n',
324 b'updated %s in %.4f seconds\n',
324 _branchcachedesc(repo),
325 _branchcachedesc(repo),
325 duration,
326 duration,
326 )
327 )
327 return max_rev
328 return max_rev
328
329
329 def _process_new(
330 def _process_new(
330 self,
331 self,
331 repo,
332 repo,
332 newbranches,
333 newbranches,
333 new_closed,
334 new_closed,
334 obs_ignored,
335 obs_ignored,
335 max_rev,
336 max_rev,
336 ):
337 ):
337 """update the branchmap from a set of new information"""
338 """update the branchmap from a set of new information"""
338 # Delay fetching the topological heads until they are needed.
339 # Delay fetching the topological heads until they are needed.
339 # A repository without non-continous branches can skip this part.
340 # A repository without non-continous branches can skip this part.
340 topoheads = None
341 topoheads = None
341
342
342 cl = repo.changelog
343 cl = repo.changelog
343 getbranchinfo = repo.revbranchcache().branchinfo
344 getbranchinfo = repo.revbranchcache().branchinfo
344 # Faster than using ctx.obsolete()
345 # Faster than using ctx.obsolete()
345 obsrevs = obsolete.getrevs(repo, b'obsolete')
346 obsrevs = obsolete.getrevs(repo, b'obsolete')
346
347
347 # If a changeset is visible, its parents must be visible too, so
348 # If a changeset is visible, its parents must be visible too, so
348 # use the faster unfiltered parent accessor.
349 # use the faster unfiltered parent accessor.
349 parentrevs = cl._uncheckedparentrevs
350 parentrevs = cl._uncheckedparentrevs
350
351
351 for branch, newheadrevs in newbranches.items():
352 for branch, newheadrevs in newbranches.items():
352 # For every branch, compute the new branchheads.
353 # For every branch, compute the new branchheads.
353 # A branchhead is a revision such that no descendant is on
354 # A branchhead is a revision such that no descendant is on
354 # the same branch.
355 # the same branch.
355 #
356 #
356 # The branchheads are computed iteratively in revision order.
357 # The branchheads are computed iteratively in revision order.
357 # This ensures topological order, i.e. parents are processed
358 # This ensures topological order, i.e. parents are processed
358 # before their children. Ancestors are inclusive here, i.e.
359 # before their children. Ancestors are inclusive here, i.e.
359 # any revision is an ancestor of itself.
360 # any revision is an ancestor of itself.
360 #
361 #
361 # Core observations:
362 # Core observations:
362 # - The current revision is always a branchhead for the
363 # - The current revision is always a branchhead for the
363 # repository up to that point.
364 # repository up to that point.
364 # - It is the first revision of the branch if and only if
365 # - It is the first revision of the branch if and only if
365 # there was no branchhead before. In that case, it is the
366 # there was no branchhead before. In that case, it is the
366 # only branchhead as there are no possible ancestors on
367 # only branchhead as there are no possible ancestors on
367 # the same branch.
368 # the same branch.
368 # - If a parent is on the same branch, a branchhead can
369 # - If a parent is on the same branch, a branchhead can
369 # only be an ancestor of that parent, if it is parent
370 # only be an ancestor of that parent, if it is parent
370 # itself. Otherwise it would have been removed as ancestor
371 # itself. Otherwise it would have been removed as ancestor
371 # of that parent before.
372 # of that parent before.
372 # - Therefore, if all parents are on the same branch, they
373 # - Therefore, if all parents are on the same branch, they
373 # can just be removed from the branchhead set.
374 # can just be removed from the branchhead set.
374 # - If one parent is on the same branch and the other is not
375 # - If one parent is on the same branch and the other is not
375 # and there was exactly one branchhead known, the existing
376 # and there was exactly one branchhead known, the existing
376 # branchhead can only be an ancestor if it is the parent.
377 # branchhead can only be an ancestor if it is the parent.
377 # Otherwise it would have been removed as ancestor of
378 # Otherwise it would have been removed as ancestor of
378 # the parent before. The other parent therefore can't have
379 # the parent before. The other parent therefore can't have
379 # a branchhead as ancestor.
380 # a branchhead as ancestor.
380 # - In all other cases, the parents on different branches
381 # - In all other cases, the parents on different branches
381 # could have a branchhead as ancestor. Those parents are
382 # could have a branchhead as ancestor. Those parents are
382 # kept in the "uncertain" set. If all branchheads are also
383 # kept in the "uncertain" set. If all branchheads are also
383 # topological heads, they can't have descendants and further
384 # topological heads, they can't have descendants and further
384 # checks can be skipped. Otherwise, the ancestors of the
385 # checks can be skipped. Otherwise, the ancestors of the
385 # "uncertain" set are removed from branchheads.
386 # "uncertain" set are removed from branchheads.
386 # This computation is heavy and avoided if at all possible.
387 # This computation is heavy and avoided if at all possible.
387 bheads = self._entries.get(branch, [])
388 bheads = self._entries.get(branch, [])
388 bheadset = {cl.rev(node) for node in bheads}
389 bheadset = {cl.rev(node) for node in bheads}
389 uncertain = set()
390 uncertain = set()
390 for newrev in sorted(newheadrevs):
391 for newrev in sorted(newheadrevs):
391 if not bheadset:
392 if not bheadset:
392 bheadset.add(newrev)
393 bheadset.add(newrev)
393 continue
394 continue
394
395
395 parents = [p for p in parentrevs(newrev) if p != nullrev]
396 parents = [p for p in parentrevs(newrev) if p != nullrev]
396 samebranch = set()
397 samebranch = set()
397 otherbranch = set()
398 otherbranch = set()
398 obsparents = set()
399 obsparents = set()
399 for p in parents:
400 for p in parents:
400 if p in obsrevs:
401 if p in obsrevs:
401 # We ignored this obsolete changeset earlier, but now
402 # We ignored this obsolete changeset earlier, but now
402 # that it has non-ignored children, we need to make
403 # that it has non-ignored children, we need to make
403 # sure their ancestors are not considered heads. To
404 # sure their ancestors are not considered heads. To
404 # achieve that, we will simply treat this obsolete
405 # achieve that, we will simply treat this obsolete
405 # changeset as a parent from other branch.
406 # changeset as a parent from other branch.
406 obsparents.add(p)
407 obsparents.add(p)
407 elif p in bheadset or getbranchinfo(p)[0] == branch:
408 elif p in bheadset or getbranchinfo(p)[0] == branch:
408 samebranch.add(p)
409 samebranch.add(p)
409 else:
410 else:
410 otherbranch.add(p)
411 otherbranch.add(p)
411 if not (len(bheadset) == len(samebranch) == 1):
412 if not (len(bheadset) == len(samebranch) == 1):
412 uncertain.update(otherbranch)
413 uncertain.update(otherbranch)
413 uncertain.update(obsparents)
414 uncertain.update(obsparents)
414 bheadset.difference_update(samebranch)
415 bheadset.difference_update(samebranch)
415 bheadset.add(newrev)
416 bheadset.add(newrev)
416
417
417 if uncertain:
418 if uncertain:
418 if topoheads is None:
419 if topoheads is None:
419 topoheads = set(cl.headrevs())
420 topoheads = set(cl.headrevs())
420 if bheadset - topoheads:
421 if bheadset - topoheads:
421 floorrev = min(bheadset)
422 floorrev = min(bheadset)
422 if floorrev <= max(uncertain):
423 if floorrev <= max(uncertain):
423 ancestors = set(cl.ancestors(uncertain, floorrev))
424 ancestors = set(cl.ancestors(uncertain, floorrev))
424 bheadset -= ancestors
425 bheadset -= ancestors
425 if bheadset:
426 if bheadset:
426 self[branch] = [cl.node(rev) for rev in sorted(bheadset)]
427 self[branch] = [cl.node(rev) for rev in sorted(bheadset)]
427
428
428
429
429 STATE_CLEAN = 1
430 STATE_CLEAN = 1
430 STATE_INHERITED = 2
431 STATE_INHERITED = 2
431 STATE_DIRTY = 3
432 STATE_DIRTY = 3
432
433
433
434
434 class _LocalBranchCache(_BaseBranchCache):
435 class _LocalBranchCache(_BaseBranchCache):
435 """base class of branch-map info for a local repo or repoview"""
436 """base class of branch-map info for a local repo or repoview"""
436
437
437 _base_filename = None
438 _base_filename = None
438 _default_key_hashes: Tuple[bytes] = cast(Tuple[bytes], ())
439 _default_key_hashes: Tuple[bytes] = cast(Tuple[bytes], ())
439
440
440 def __init__(
441 def __init__(
441 self,
442 self,
442 repo: "localrepo.localrepository",
443 repo: "localrepo.localrepository",
443 entries: Union[
444 entries: Union[
444 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
445 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
445 ] = (),
446 ] = (),
446 tipnode: Optional[bytes] = None,
447 tipnode: Optional[bytes] = None,
447 tiprev: Optional[int] = nullrev,
448 tiprev: Optional[int] = nullrev,
448 key_hashes: Optional[Tuple[bytes]] = None,
449 key_hashes: Optional[Tuple[bytes]] = None,
449 closednodes: Optional[Set[bytes]] = None,
450 closednodes: Optional[Set[bytes]] = None,
450 hasnode: Optional[Callable[[bytes], bool]] = None,
451 hasnode: Optional[Callable[[bytes], bool]] = None,
451 verify_node: bool = False,
452 verify_node: bool = False,
452 inherited: bool = False,
453 inherited: bool = False,
453 ) -> None:
454 ) -> None:
454 """hasnode is a function which can be used to verify whether changelog
455 """hasnode is a function which can be used to verify whether changelog
455 has a given node or not. If it's not provided, we assume that every node
456 has a given node or not. If it's not provided, we assume that every node
456 we have exists in changelog"""
457 we have exists in changelog"""
457 self._filtername = repo.filtername
458 self._filtername = repo.filtername
458 if tipnode is None:
459 if tipnode is None:
459 self.tipnode = repo.nullid
460 self.tipnode = repo.nullid
460 else:
461 else:
461 self.tipnode = tipnode
462 self.tipnode = tipnode
462 self.tiprev = tiprev
463 self.tiprev = tiprev
463 if key_hashes is None:
464 if key_hashes is None:
464 self.key_hashes = self._default_key_hashes
465 self.key_hashes = self._default_key_hashes
465 else:
466 else:
466 self.key_hashes = key_hashes
467 self.key_hashes = key_hashes
467 self._state = STATE_CLEAN
468 self._state = STATE_CLEAN
468 if inherited:
469 if inherited:
469 self._state = STATE_INHERITED
470 self._state = STATE_INHERITED
470
471
471 super().__init__(repo=repo, entries=entries, closed_nodes=closednodes)
472 super().__init__(repo=repo, entries=entries, closed_nodes=closednodes)
472 # closednodes is a set of nodes that close their branch. If the branch
473 # closednodes is a set of nodes that close their branch. If the branch
473 # cache has been updated, it may contain nodes that are no longer
474 # cache has been updated, it may contain nodes that are no longer
474 # heads.
475 # heads.
475
476
476 # Do we need to verify branch at all ?
477 # Do we need to verify branch at all ?
477 self._verify_node = verify_node
478 self._verify_node = verify_node
478 # branches for which nodes are verified
479 # branches for which nodes are verified
479 self._verifiedbranches = set()
480 self._verifiedbranches = set()
480 self._hasnode = None
481 self._hasnode = None
481 if self._verify_node:
482 if self._verify_node:
482 self._hasnode = repo.changelog.hasnode
483 self._hasnode = repo.changelog.hasnode
483
484
484 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
485 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
485 raise NotImplementedError
486 raise NotImplementedError
486
487
488 def _ensure_populated(self, repo):
489 """make sure any lazily loaded values are fully populated"""
490
487 def validfor(self, repo):
491 def validfor(self, repo):
488 """check that cache contents are valid for (a subset of) this repo
492 """check that cache contents are valid for (a subset of) this repo
489
493
490 - False when the order of changesets changed or if we detect a strip.
494 - False when the order of changesets changed or if we detect a strip.
491 - True when cache is up-to-date for the current repo or its subset."""
495 - True when cache is up-to-date for the current repo or its subset."""
492 try:
496 try:
493 node = repo.changelog.node(self.tiprev)
497 node = repo.changelog.node(self.tiprev)
494 except IndexError:
498 except IndexError:
495 # changesets were stripped and now we don't even have enough to
499 # changesets were stripped and now we don't even have enough to
496 # find tiprev
500 # find tiprev
497 return False
501 return False
498 if self.tipnode != node:
502 if self.tipnode != node:
499 # tiprev doesn't correspond to tipnode: repo was stripped, or this
503 # tiprev doesn't correspond to tipnode: repo was stripped, or this
500 # repo has a different order of changesets
504 # repo has a different order of changesets
501 return False
505 return False
502 repo_key_hashes = self._compute_key_hashes(repo)
506 repo_key_hashes = self._compute_key_hashes(repo)
503 # hashes don't match if this repo view has a different set of filtered
507 # hashes don't match if this repo view has a different set of filtered
504 # revisions (e.g. due to phase changes) or obsolete revisions (e.g.
508 # revisions (e.g. due to phase changes) or obsolete revisions (e.g.
505 # history was rewritten)
509 # history was rewritten)
506 return self.key_hashes == repo_key_hashes
510 return self.key_hashes == repo_key_hashes
507
511
508 @classmethod
512 @classmethod
509 def fromfile(cls, repo):
513 def fromfile(cls, repo):
510 f = None
514 f = None
511 try:
515 try:
512 f = repo.cachevfs(cls._filename(repo))
516 f = repo.cachevfs(cls._filename(repo))
513 lineiter = iter(f)
517 lineiter = iter(f)
514 init_kwargs = cls._load_header(repo, lineiter)
518 init_kwargs = cls._load_header(repo, lineiter)
515 bcache = cls(
519 bcache = cls(
516 repo,
520 repo,
517 verify_node=True,
521 verify_node=True,
518 **init_kwargs,
522 **init_kwargs,
519 )
523 )
520 if not bcache.validfor(repo):
524 if not bcache.validfor(repo):
521 # invalidate the cache
525 # invalidate the cache
522 raise ValueError('tip differs')
526 raise ValueError('tip differs')
523 bcache._load_heads(repo, lineiter)
527 bcache._load_heads(repo, lineiter)
524 except (IOError, OSError):
528 except (IOError, OSError):
525 return None
529 return None
526
530
527 except Exception as inst:
531 except Exception as inst:
528 if repo.ui.debugflag:
532 if repo.ui.debugflag:
529 msg = b'invalid %s: %s\n'
533 msg = b'invalid %s: %s\n'
530 msg %= (
534 msg %= (
531 _branchcachedesc(repo),
535 _branchcachedesc(repo),
532 stringutil.forcebytestr(inst),
536 stringutil.forcebytestr(inst),
533 )
537 )
534 repo.ui.debug(msg)
538 repo.ui.debug(msg)
535 bcache = None
539 bcache = None
536
540
537 finally:
541 finally:
538 if f:
542 if f:
539 f.close()
543 f.close()
540
544
541 return bcache
545 return bcache
542
546
543 @classmethod
547 @classmethod
544 def _load_header(cls, repo, lineiter) -> "dict[str, Any]":
548 def _load_header(cls, repo, lineiter) -> "dict[str, Any]":
545 raise NotImplementedError
549 raise NotImplementedError
546
550
547 def _load_heads(self, repo, lineiter):
551 def _load_heads(self, repo, lineiter):
548 """fully loads the branchcache by reading from the file using the line
552 """fully loads the branchcache by reading from the file using the line
549 iterator passed"""
553 iterator passed"""
550 for line in lineiter:
554 for line in lineiter:
551 line = line.rstrip(b'\n')
555 line = line.rstrip(b'\n')
552 if not line:
556 if not line:
553 continue
557 continue
554 node, state, label = line.split(b" ", 2)
558 node, state, label = line.split(b" ", 2)
555 if state not in b'oc':
559 if state not in b'oc':
556 raise ValueError('invalid branch state')
560 raise ValueError('invalid branch state')
557 label = encoding.tolocal(label.strip())
561 label = encoding.tolocal(label.strip())
558 node = bin(node)
562 node = bin(node)
559 self._entries.setdefault(label, []).append(node)
563 self._entries.setdefault(label, []).append(node)
560 if state == b'c':
564 if state == b'c':
561 self._closednodes.add(node)
565 self._closednodes.add(node)
562
566
563 @classmethod
567 @classmethod
564 def _filename(cls, repo):
568 def _filename(cls, repo):
565 """name of a branchcache file for a given repo or repoview"""
569 """name of a branchcache file for a given repo or repoview"""
566 filename = cls._base_filename
570 filename = cls._base_filename
567 assert filename is not None
571 assert filename is not None
568 if repo.filtername:
572 if repo.filtername:
569 filename = b'%s-%s' % (filename, repo.filtername)
573 filename = b'%s-%s' % (filename, repo.filtername)
570 return filename
574 return filename
571
575
572 def inherit_for(self, repo):
576 def inherit_for(self, repo):
573 """return a deep copy of the branchcache object"""
577 """return a deep copy of the branchcache object"""
574 assert repo.filtername != self._filtername
578 assert repo.filtername != self._filtername
575 other = type(self)(
579 other = type(self)(
576 repo=repo,
580 repo=repo,
577 # we always do a shally copy of self._entries, and the values is
581 # we always do a shally copy of self._entries, and the values is
578 # always replaced, so no need to deepcopy until the above remains
582 # always replaced, so no need to deepcopy until the above remains
579 # true.
583 # true.
580 entries=self._entries,
584 entries=self._entries,
581 tipnode=self.tipnode,
585 tipnode=self.tipnode,
582 tiprev=self.tiprev,
586 tiprev=self.tiprev,
583 key_hashes=self.key_hashes,
587 key_hashes=self.key_hashes,
584 closednodes=set(self._closednodes),
588 closednodes=set(self._closednodes),
585 verify_node=self._verify_node,
589 verify_node=self._verify_node,
586 inherited=True,
590 inherited=True,
587 )
591 )
588 # also copy information about the current verification state
592 # also copy information about the current verification state
589 other._verifiedbranches = set(self._verifiedbranches)
593 other._verifiedbranches = set(self._verifiedbranches)
590 return other
594 return other
591
595
592 def sync_disk(self, repo):
596 def sync_disk(self, repo):
593 """synchronise the on disk file with the cache state
597 """synchronise the on disk file with the cache state
594
598
595 If new value specific to this filter level need to be written, the file
599 If new value specific to this filter level need to be written, the file
596 will be updated, if the state of the branchcache is inherited from a
600 will be updated, if the state of the branchcache is inherited from a
597 subset, any stalled on disk file will be deleted.
601 subset, any stalled on disk file will be deleted.
598
602
599 That method does nothing if there is nothing to do.
603 That method does nothing if there is nothing to do.
600 """
604 """
601 if self._state == STATE_DIRTY:
605 if self._state == STATE_DIRTY:
602 self.write(repo)
606 self.write(repo)
603 elif self._state == STATE_INHERITED:
607 elif self._state == STATE_INHERITED:
604 filename = self._filename(repo)
608 filename = self._filename(repo)
605 repo.cachevfs.tryunlink(filename)
609 repo.cachevfs.tryunlink(filename)
606
610
607 def write(self, repo):
611 def write(self, repo):
608 assert self._filtername == repo.filtername, (
612 assert self._filtername == repo.filtername, (
609 self._filtername,
613 self._filtername,
610 repo.filtername,
614 repo.filtername,
611 )
615 )
612 assert self._state == STATE_DIRTY, self._state
616 assert self._state == STATE_DIRTY, self._state
613 # This method should not be called during an open transaction
617 # This method should not be called during an open transaction
614 tr = repo.currenttransaction()
618 tr = repo.currenttransaction()
615 if not getattr(tr, 'finalized', True):
619 if not getattr(tr, 'finalized', True):
616 msg = "writing branchcache in the middle of a transaction"
620 msg = "writing branchcache in the middle of a transaction"
617 raise error.ProgrammingError(msg)
621 raise error.ProgrammingError(msg)
618 try:
622 try:
619 filename = self._filename(repo)
623 filename = self._filename(repo)
620 with repo.cachevfs(filename, b"w", atomictemp=True) as f:
624 with repo.cachevfs(filename, b"w", atomictemp=True) as f:
621 self._write_header(f)
625 self._write_header(f)
622 nodecount = self._write_heads(repo, f)
626 nodecount = self._write_heads(repo, f)
623 repo.ui.log(
627 repo.ui.log(
624 b'branchcache',
628 b'branchcache',
625 b'wrote %s with %d labels and %d nodes\n',
629 b'wrote %s with %d labels and %d nodes\n',
626 _branchcachedesc(repo),
630 _branchcachedesc(repo),
627 len(self._entries),
631 len(self._entries),
628 nodecount,
632 nodecount,
629 )
633 )
630 self._state = STATE_CLEAN
634 self._state = STATE_CLEAN
631 except (IOError, OSError, error.Abort) as inst:
635 except (IOError, OSError, error.Abort) as inst:
632 # Abort may be raised by read only opener, so log and continue
636 # Abort may be raised by read only opener, so log and continue
633 repo.ui.debug(
637 repo.ui.debug(
634 b"couldn't write branch cache: %s\n"
638 b"couldn't write branch cache: %s\n"
635 % stringutil.forcebytestr(inst)
639 % stringutil.forcebytestr(inst)
636 )
640 )
637
641
638 def _write_header(self, fp) -> None:
642 def _write_header(self, fp) -> None:
639 raise NotImplementedError
643 raise NotImplementedError
640
644
641 def _write_heads(self, repo, fp) -> int:
645 def _write_heads(self, repo, fp) -> int:
642 """write list of heads to a file
646 """write list of heads to a file
643
647
644 Return the number of heads written."""
648 Return the number of heads written."""
645 nodecount = 0
649 nodecount = 0
646 for label, nodes in sorted(self._entries.items()):
650 for label, nodes in sorted(self._entries.items()):
647 label = encoding.fromlocal(label)
651 label = encoding.fromlocal(label)
648 for node in nodes:
652 for node in nodes:
649 nodecount += 1
653 nodecount += 1
650 if node in self._closednodes:
654 if node in self._closednodes:
651 state = b'c'
655 state = b'c'
652 else:
656 else:
653 state = b'o'
657 state = b'o'
654 fp.write(b"%s %s %s\n" % (hex(node), state, label))
658 fp.write(b"%s %s %s\n" % (hex(node), state, label))
655 return nodecount
659 return nodecount
656
660
657 def _verifybranch(self, branch):
661 def _verifybranch(self, branch):
658 """verify head nodes for the given branch."""
662 """verify head nodes for the given branch."""
659 if not self._verify_node:
663 if not self._verify_node:
660 return
664 return
661 if branch not in self._entries or branch in self._verifiedbranches:
665 if branch not in self._entries or branch in self._verifiedbranches:
662 return
666 return
663 assert self._hasnode is not None
667 assert self._hasnode is not None
664 for n in self._entries[branch]:
668 for n in self._entries[branch]:
665 if not self._hasnode(n):
669 if not self._hasnode(n):
666 _unknownnode(n)
670 _unknownnode(n)
667
671
668 self._verifiedbranches.add(branch)
672 self._verifiedbranches.add(branch)
669
673
670 def _verifyall(self):
674 def _verifyall(self):
671 """verifies nodes of all the branches"""
675 """verifies nodes of all the branches"""
672 for b in self._entries.keys():
676 for b in self._entries.keys():
673 if b not in self._verifiedbranches:
677 if b not in self._verifiedbranches:
674 self._verifybranch(b)
678 self._verifybranch(b)
675
679
676 def __getitem__(self, key):
680 def __getitem__(self, key):
677 self._verifybranch(key)
681 self._verifybranch(key)
678 return super().__getitem__(key)
682 return super().__getitem__(key)
679
683
680 def __contains__(self, key):
684 def __contains__(self, key):
681 self._verifybranch(key)
685 self._verifybranch(key)
682 return super().__contains__(key)
686 return super().__contains__(key)
683
687
684 def iteritems(self):
688 def iteritems(self):
685 self._verifyall()
689 self._verifyall()
686 return super().iteritems()
690 return super().iteritems()
687
691
688 items = iteritems
692 items = iteritems
689
693
690 def iterheads(self):
694 def iterheads(self):
691 """returns all the heads"""
695 """returns all the heads"""
692 self._verifyall()
696 self._verifyall()
693 return super().iterheads()
697 return super().iterheads()
694
698
695 def hasbranch(self, label):
699 def hasbranch(self, label):
696 """checks whether a branch of this name exists or not"""
700 """checks whether a branch of this name exists or not"""
697 self._verifybranch(label)
701 self._verifybranch(label)
698 return super().hasbranch(label)
702 return super().hasbranch(label)
699
703
700 def branchheads(self, branch, closed=False):
704 def branchheads(self, branch, closed=False):
701 self._verifybranch(branch)
705 self._verifybranch(branch)
702 return super().branchheads(branch, closed=closed)
706 return super().branchheads(branch, closed=closed)
703
707
704 def update(self, repo, revgen):
708 def update(self, repo, revgen):
705 assert self._filtername == repo.filtername, (
709 assert self._filtername == repo.filtername, (
706 self._filtername,
710 self._filtername,
707 repo.filtername,
711 repo.filtername,
708 )
712 )
709 cl = repo.changelog
713 cl = repo.changelog
710 max_rev = super().update(repo, revgen)
714 max_rev = super().update(repo, revgen)
711 # new tip revision which we found after iterating items from new
715 # new tip revision which we found after iterating items from new
712 # branches
716 # branches
713 if max_rev is not None and max_rev > self.tiprev:
717 if max_rev is not None and max_rev > self.tiprev:
714 self.tiprev = max_rev
718 self.tiprev = max_rev
715 self.tipnode = cl.node(max_rev)
719 self.tipnode = cl.node(max_rev)
716 else:
720 else:
717 # We should not be here is if this is false
721 # We should not be here is if this is false
718 assert cl.node(self.tiprev) == self.tipnode
722 assert cl.node(self.tiprev) == self.tipnode
719
723
720 if not self.validfor(repo):
724 if not self.validfor(repo):
721 # the tiprev and tipnode should be aligned, so if the current repo
725 # the tiprev and tipnode should be aligned, so if the current repo
722 # is not seens as valid this is because old cache key is now
726 # is not seens as valid this is because old cache key is now
723 # invalid for the repo.
727 # invalid for the repo.
724 #
728 #
725 # However. we've just updated the cache and we assume it's valid,
729 # However. we've just updated the cache and we assume it's valid,
726 # so let's make the cache key valid as well by recomputing it from
730 # so let's make the cache key valid as well by recomputing it from
727 # the cached data
731 # the cached data
728 self.key_hashes = self._compute_key_hashes(repo)
732 self.key_hashes = self._compute_key_hashes(repo)
729 self.filteredhash = scmutil.combined_filtered_and_obsolete_hash(
733 self.filteredhash = scmutil.combined_filtered_and_obsolete_hash(
730 repo,
734 repo,
731 self.tiprev,
735 self.tiprev,
732 )
736 )
733
737
734 self._state = STATE_DIRTY
738 self._state = STATE_DIRTY
735 tr = repo.currenttransaction()
739 tr = repo.currenttransaction()
736 if getattr(tr, 'finalized', True):
740 if getattr(tr, 'finalized', True):
737 # Avoid premature writing.
741 # Avoid premature writing.
738 #
742 #
739 # (The cache warming setup by localrepo will update the file later.)
743 # (The cache warming setup by localrepo will update the file later.)
740 self.write(repo)
744 self.write(repo)
741
745
742
746
743 def branch_cache_from_file(repo) -> Optional[_LocalBranchCache]:
747 def branch_cache_from_file(repo) -> Optional[_LocalBranchCache]:
744 """Build a branch cache from on-disk data if possible
748 """Build a branch cache from on-disk data if possible
745
749
746 Return a branch cache of the right format depending of the repository.
750 Return a branch cache of the right format depending of the repository.
747 """
751 """
748 if repo.ui.configbool(b"experimental", b"branch-cache-v3"):
752 if repo.ui.configbool(b"experimental", b"branch-cache-v3"):
749 return BranchCacheV3.fromfile(repo)
753 return BranchCacheV3.fromfile(repo)
750 else:
754 else:
751 return BranchCacheV2.fromfile(repo)
755 return BranchCacheV2.fromfile(repo)
752
756
753
757
754 def new_branch_cache(repo, *args, **kwargs):
758 def new_branch_cache(repo, *args, **kwargs):
755 """Build a new branch cache from argument
759 """Build a new branch cache from argument
756
760
757 Return a branch cache of the right format depending of the repository.
761 Return a branch cache of the right format depending of the repository.
758 """
762 """
759 if repo.ui.configbool(b"experimental", b"branch-cache-v3"):
763 if repo.ui.configbool(b"experimental", b"branch-cache-v3"):
760 return BranchCacheV3(repo, *args, **kwargs)
764 return BranchCacheV3(repo, *args, **kwargs)
761 else:
765 else:
762 return BranchCacheV2(repo, *args, **kwargs)
766 return BranchCacheV2(repo, *args, **kwargs)
763
767
764
768
765 class BranchCacheV2(_LocalBranchCache):
769 class BranchCacheV2(_LocalBranchCache):
766 """a branch cache using version 2 of the format on disk
770 """a branch cache using version 2 of the format on disk
767
771
768 The cache is serialized on disk in the following format:
772 The cache is serialized on disk in the following format:
769
773
770 <tip hex node> <tip rev number> [optional filtered repo hex hash]
774 <tip hex node> <tip rev number> [optional filtered repo hex hash]
771 <branch head hex node> <open/closed state> <branch name>
775 <branch head hex node> <open/closed state> <branch name>
772 <branch head hex node> <open/closed state> <branch name>
776 <branch head hex node> <open/closed state> <branch name>
773 ...
777 ...
774
778
775 The first line is used to check if the cache is still valid. If the
779 The first line is used to check if the cache is still valid. If the
776 branch cache is for a filtered repo view, an optional third hash is
780 branch cache is for a filtered repo view, an optional third hash is
777 included that hashes the hashes of all filtered and obsolete revisions.
781 included that hashes the hashes of all filtered and obsolete revisions.
778
782
779 The open/closed state is represented by a single letter 'o' or 'c'.
783 The open/closed state is represented by a single letter 'o' or 'c'.
780 This field can be used to avoid changelog reads when determining if a
784 This field can be used to avoid changelog reads when determining if a
781 branch head closes a branch or not.
785 branch head closes a branch or not.
782 """
786 """
783
787
784 _base_filename = b"branch2"
788 _base_filename = b"branch2"
785
789
786 @classmethod
790 @classmethod
787 def _load_header(cls, repo, lineiter) -> "dict[str, Any]":
791 def _load_header(cls, repo, lineiter) -> "dict[str, Any]":
788 """parse the head of a branchmap file
792 """parse the head of a branchmap file
789
793
790 return parameters to pass to a newly created class instance.
794 return parameters to pass to a newly created class instance.
791 """
795 """
792 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2)
796 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2)
793 last, lrev = cachekey[:2]
797 last, lrev = cachekey[:2]
794 last, lrev = bin(last), int(lrev)
798 last, lrev = bin(last), int(lrev)
795 filteredhash = ()
799 filteredhash = ()
796 if len(cachekey) > 2:
800 if len(cachekey) > 2:
797 filteredhash = (bin(cachekey[2]),)
801 filteredhash = (bin(cachekey[2]),)
798 return {
802 return {
799 "tipnode": last,
803 "tipnode": last,
800 "tiprev": lrev,
804 "tiprev": lrev,
801 "key_hashes": filteredhash,
805 "key_hashes": filteredhash,
802 }
806 }
803
807
804 def _write_header(self, fp) -> None:
808 def _write_header(self, fp) -> None:
805 """write the branch cache header to a file"""
809 """write the branch cache header to a file"""
806 cachekey = [hex(self.tipnode), b'%d' % self.tiprev]
810 cachekey = [hex(self.tipnode), b'%d' % self.tiprev]
807 if self.key_hashes:
811 if self.key_hashes:
808 cachekey.append(hex(self.key_hashes[0]))
812 cachekey.append(hex(self.key_hashes[0]))
809 fp.write(b" ".join(cachekey) + b'\n')
813 fp.write(b" ".join(cachekey) + b'\n')
810
814
811 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
815 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
812 """return the cache key hashes that match this repoview state"""
816 """return the cache key hashes that match this repoview state"""
813 filtered_hash = scmutil.combined_filtered_and_obsolete_hash(
817 filtered_hash = scmutil.combined_filtered_and_obsolete_hash(
814 repo,
818 repo,
815 self.tiprev,
819 self.tiprev,
816 needobsolete=True,
820 needobsolete=True,
817 )
821 )
818 keys: Tuple[bytes] = cast(Tuple[bytes], ())
822 keys: Tuple[bytes] = cast(Tuple[bytes], ())
819 if filtered_hash is not None:
823 if filtered_hash is not None:
820 keys: Tuple[bytes] = (filtered_hash,)
824 keys: Tuple[bytes] = (filtered_hash,)
821 return keys
825 return keys
822
826
823
827
824 class BranchCacheV3(_LocalBranchCache):
828 class BranchCacheV3(_LocalBranchCache):
825 """a branch cache using version 3 of the format on disk
829 """a branch cache using version 3 of the format on disk
826
830
827 This version is still EXPERIMENTAL and the format is subject to changes.
831 This version is still EXPERIMENTAL and the format is subject to changes.
828
832
829 The cache is serialized on disk in the following format:
833 The cache is serialized on disk in the following format:
830
834
831 <cache-key-xxx>=<xxx-value> <cache-key-yyy>=<yyy-value> […]
835 <cache-key-xxx>=<xxx-value> <cache-key-yyy>=<yyy-value> […]
832 <branch head hex node> <open/closed state> <branch name>
836 <branch head hex node> <open/closed state> <branch name>
833 <branch head hex node> <open/closed state> <branch name>
837 <branch head hex node> <open/closed state> <branch name>
834 ...
838 ...
835
839
836 The first line is used to check if the cache is still valid. It is a series
840 The first line is used to check if the cache is still valid. It is a series
837 of key value pair. The following key are recognized:
841 of key value pair. The following key are recognized:
838
842
839 - tip-rev: the rev-num of the tip-most revision seen by this cache
843 - tip-rev: the rev-num of the tip-most revision seen by this cache
840 - tip-node: the node-id of the tip-most revision sen by this cache
844 - tip-node: the node-id of the tip-most revision sen by this cache
841 - filtered-hash: the hash of all filtered revisions (before tip-rev)
845 - filtered-hash: the hash of all filtered revisions (before tip-rev)
842 ignored by this cache.
846 ignored by this cache.
843 - obsolete-hash: the hash of all non-filtered obsolete revisions (before
847 - obsolete-hash: the hash of all non-filtered obsolete revisions (before
844 tip-rev) ignored by this cache.
848 tip-rev) ignored by this cache.
845
849
846 The tip-rev is used to know how far behind the value in the file are
850 The tip-rev is used to know how far behind the value in the file are
847 compared to the current repository state.
851 compared to the current repository state.
848
852
849 The tip-node, filtered-hash and obsolete-hash are used to detect if this
853 The tip-node, filtered-hash and obsolete-hash are used to detect if this
850 cache can be used for this repository state at all.
854 cache can be used for this repository state at all.
851
855
852 The open/closed state is represented by a single letter 'o' or 'c'.
856 The open/closed state is represented by a single letter 'o' or 'c'.
853 This field can be used to avoid changelog reads when determining if a
857 This field can be used to avoid changelog reads when determining if a
854 branch head closes a branch or not.
858 branch head closes a branch or not.
855
859
856 Topological heads are not included in the listing and should be dispatched
860 Topological heads are not included in the listing and should be dispatched
857 on the right branch at read time. Obsolete topological heads should be
861 on the right branch at read time. Obsolete topological heads should be
858 ignored.
862 ignored.
859 """
863 """
860
864
861 _base_filename = b"branch3"
865 _base_filename = b"branch3"
862 _default_key_hashes = (None, None)
866 _default_key_hashes = (None, None)
863
867
864 def _get_topo_heads(self, repo) -> List[int]:
868 def __init__(self, *args, pure_topo_branch=None, **kwargs):
869 super().__init__(*args, **kwargs)
870 self._pure_topo_branch = pure_topo_branch
871 self._needs_populate = self._pure_topo_branch is not None
872
873 def inherit_for(self, repo):
874 new = super().inherit_for(repo)
875 new._pure_topo_branch = self._pure_topo_branch
876 new._needs_populate = self._needs_populate
877 return new
878
879 def _get_topo_heads(self, repo):
865 """returns the topological head of a repoview content up to self.tiprev"""
880 """returns the topological head of a repoview content up to self.tiprev"""
866 cl = repo.changelog
881 cl = repo.changelog
867 if self.tiprev == nullrev:
882 if self.tiprev == nullrev:
868 return []
883 return []
869 elif self.tiprev == cl.tiprev():
884 elif self.tiprev == cl.tiprev():
870 return cl.headrevs()
885 return cl.headrevs()
871 else:
886 else:
872 # XXX passing tiprev as ceiling of cl.headrevs could be faster
887 # XXX passing tiprev as ceiling of cl.headrevs could be faster
873 heads = cl.headrevs(cl.revs(stop=self.tiprev))
888 heads = cl.headrevs(cl.revs(stop=self.tiprev))
874 return heads
889 return heads
875
890
876 def _write_header(self, fp) -> None:
891 def _write_header(self, fp) -> None:
877 cache_keys = {
892 cache_keys = {
878 b"tip-node": hex(self.tipnode),
893 b"tip-node": hex(self.tipnode),
879 b"tip-rev": b'%d' % self.tiprev,
894 b"tip-rev": b'%d' % self.tiprev,
880 }
895 }
881 if self.key_hashes:
896 if self.key_hashes:
882 if self.key_hashes[0] is not None:
897 if self.key_hashes[0] is not None:
883 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0])
898 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0])
884 if self.key_hashes[1] is not None:
899 if self.key_hashes[1] is not None:
885 cache_keys[b"obsolete-hash"] = hex(self.key_hashes[1])
900 cache_keys[b"obsolete-hash"] = hex(self.key_hashes[1])
901 if self._pure_topo_branch is not None:
902 cache_keys[b"topo-mode"] = b"pure"
886 pieces = (b"%s=%s" % i for i in sorted(cache_keys.items()))
903 pieces = (b"%s=%s" % i for i in sorted(cache_keys.items()))
887 fp.write(b" ".join(pieces) + b'\n')
904 fp.write(b" ".join(pieces) + b'\n')
905 if self._pure_topo_branch is not None:
906 label = encoding.fromlocal(self._pure_topo_branch)
907 fp.write(label + b'\n')
888
908
889 def _write_heads(self, repo, fp) -> int:
909 def _write_heads(self, repo, fp) -> int:
890 """write list of heads to a file
910 """write list of heads to a file
891
911
892 Return the number of heads written."""
912 Return the number of heads written."""
893 nodecount = 0
913 nodecount = 0
894 topo_heads = set(self._get_topo_heads(repo))
914 topo_heads = None
915 if self._pure_topo_branch is None:
916 topo_heads = set(self._get_topo_heads(repo))
895 to_rev = repo.changelog.index.rev
917 to_rev = repo.changelog.index.rev
896 for label, nodes in sorted(self._entries.items()):
918 for label, nodes in sorted(self._entries.items()):
919 if label == self._pure_topo_branch:
920 # not need to write anything the header took care of that
921 continue
897 label = encoding.fromlocal(label)
922 label = encoding.fromlocal(label)
898 for node in nodes:
923 for node in nodes:
899 rev = to_rev(node)
924 if topo_heads is not None:
900 if rev in topo_heads:
925 rev = to_rev(node)
901 continue
926 if rev in topo_heads:
927 continue
902 if node in self._closednodes:
928 if node in self._closednodes:
903 state = b'c'
929 state = b'c'
904 else:
930 else:
905 state = b'o'
931 state = b'o'
906 nodecount += 1
932 nodecount += 1
907 fp.write(b"%s %s %s\n" % (hex(node), state, label))
933 fp.write(b"%s %s %s\n" % (hex(node), state, label))
908 return nodecount
934 return nodecount
909
935
910 @classmethod
936 @classmethod
911 def _load_header(cls, repo, lineiter):
937 def _load_header(cls, repo, lineiter):
912 header_line = next(lineiter)
938 header_line = next(lineiter)
913 pieces = header_line.rstrip(b'\n').split(b" ")
939 pieces = header_line.rstrip(b'\n').split(b" ")
914 cache_keys = dict(p.split(b'=', 1) for p in pieces)
940 cache_keys = dict(p.split(b'=', 1) for p in pieces)
915
941
916 args = {}
942 args = {}
917 filtered_hash = None
943 filtered_hash = None
918 obsolete_hash = None
944 obsolete_hash = None
945 has_pure_topo_heads = False
919 for k, v in cache_keys.items():
946 for k, v in cache_keys.items():
920 if k == b"tip-rev":
947 if k == b"tip-rev":
921 args["tiprev"] = int(v)
948 args["tiprev"] = int(v)
922 elif k == b"tip-node":
949 elif k == b"tip-node":
923 args["tipnode"] = bin(v)
950 args["tipnode"] = bin(v)
924 elif k == b"filtered-hash":
951 elif k == b"filtered-hash":
925 filtered_hash = bin(v)
952 filtered_hash = bin(v)
926 elif k == b"obsolete-hash":
953 elif k == b"obsolete-hash":
927 obsolete_hash = bin(v)
954 obsolete_hash = bin(v)
955 elif k == b"topo-mode":
956 if v == b"pure":
957 has_pure_topo_heads = True
958 else:
959 msg = b"unknown topo-mode: %r" % v
960 raise ValueError(msg)
928 else:
961 else:
929 msg = b"unknown cache key: %r" % k
962 msg = b"unknown cache key: %r" % k
930 raise ValueError(msg)
963 raise ValueError(msg)
931 args["key_hashes"] = (filtered_hash, obsolete_hash)
964 args["key_hashes"] = (filtered_hash, obsolete_hash)
965 if has_pure_topo_heads:
966 pure_line = next(lineiter).rstrip(b'\n')
967 args["pure_topo_branch"] = encoding.tolocal(pure_line)
932 return args
968 return args
933
969
934 def _load_heads(self, repo, lineiter):
970 def _load_heads(self, repo, lineiter):
935 """fully loads the branchcache by reading from the file using the line
971 """fully loads the branchcache by reading from the file using the line
936 iterator passed"""
972 iterator passed"""
937 super()._load_heads(repo, lineiter)
973 super()._load_heads(repo, lineiter)
974 if self._pure_topo_branch is not None:
975 # no need to read the repository heads, we know their value already.
976 return
938 cl = repo.changelog
977 cl = repo.changelog
939 getbranchinfo = repo.revbranchcache().branchinfo
978 getbranchinfo = repo.revbranchcache().branchinfo
940 obsrevs = obsolete.getrevs(repo, b'obsolete')
979 obsrevs = obsolete.getrevs(repo, b'obsolete')
941 to_node = cl.node
980 to_node = cl.node
942 touched_branch = set()
981 touched_branch = set()
943 for head in self._get_topo_heads(repo):
982 for head in self._get_topo_heads(repo):
944 if head in obsrevs:
983 if head in obsrevs:
945 continue
984 continue
946 node = to_node(head)
985 node = to_node(head)
947 branch, closed = getbranchinfo(head)
986 branch, closed = getbranchinfo(head)
948 self._entries.setdefault(branch, []).append(node)
987 self._entries.setdefault(branch, []).append(node)
949 if closed:
988 if closed:
950 self._closednodes.add(node)
989 self._closednodes.add(node)
951 touched_branch.add(branch)
990 touched_branch.add(branch)
952 to_rev = cl.index.rev
991 to_rev = cl.index.rev
953 for branch in touched_branch:
992 for branch in touched_branch:
954 self._entries[branch].sort(key=to_rev)
993 self._entries[branch].sort(key=to_rev)
955
994
956 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
995 def _compute_key_hashes(self, repo) -> Tuple[bytes]:
957 """return the cache key hashes that match this repoview state"""
996 """return the cache key hashes that match this repoview state"""
958 return scmutil.filtered_and_obsolete_hash(
997 return scmutil.filtered_and_obsolete_hash(
959 repo,
998 repo,
960 self.tiprev,
999 self.tiprev,
961 )
1000 )
962
1001
1002 def _process_new(
1003 self,
1004 repo,
1005 newbranches,
1006 new_closed,
1007 obs_ignored,
1008 max_rev,
1009 ) -> None:
1010 if (
1011 # note: the check about `obs_ignored` is too strict as the
1012 # obsolete revision could be non-topological, but lets keep
1013 # things simple for now
1014 #
1015 # The same apply to `new_closed` if the closed changeset are
1016 # not a head, we don't care that it is closed, but lets keep
1017 # things simple here too.
1018 not (obs_ignored or new_closed)
1019 and (
1020 not newbranches
1021 or (
1022 len(newbranches) == 1
1023 and (
1024 self.tiprev == nullrev
1025 or self._pure_topo_branch in newbranches
1026 )
1027 )
1028 )
1029 ):
1030 if newbranches:
1031 assert len(newbranches) == 1
1032 self._pure_topo_branch = list(newbranches.keys())[0]
1033 self._needs_populate = True
1034 self._entries.pop(self._pure_topo_branch, None)
1035 return
1036
1037 self._ensure_populated(repo)
1038 self._pure_topo_branch = None
1039 super()._process_new(
1040 repo,
1041 newbranches,
1042 new_closed,
1043 obs_ignored,
1044 max_rev,
1045 )
1046
1047 def _ensure_populated(self, repo):
1048 """make sure any lazily loaded values are fully populated"""
1049 if self._needs_populate:
1050 assert self._pure_topo_branch is not None
1051 cl = repo.changelog
1052 to_node = cl.node
1053 topo_heads = self._get_topo_heads(repo)
1054 heads = [to_node(r) for r in topo_heads]
1055 self._entries[self._pure_topo_branch] = heads
1056 self._needs_populate = False
1057
963
1058
964 class remotebranchcache(_BaseBranchCache):
1059 class remotebranchcache(_BaseBranchCache):
965 """Branchmap info for a remote connection, should not write locally"""
1060 """Branchmap info for a remote connection, should not write locally"""
966
1061
967 def __init__(
1062 def __init__(
968 self,
1063 self,
969 repo: "localrepo.localrepository",
1064 repo: "localrepo.localrepository",
970 entries: Union[
1065 entries: Union[
971 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
1066 Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]
972 ] = (),
1067 ] = (),
973 closednodes: Optional[Set[bytes]] = None,
1068 closednodes: Optional[Set[bytes]] = None,
974 ) -> None:
1069 ) -> None:
975 super().__init__(repo=repo, entries=entries, closed_nodes=closednodes)
1070 super().__init__(repo=repo, entries=entries, closed_nodes=closednodes)
976
1071
977
1072
978 # Revision branch info cache
1073 # Revision branch info cache
979
1074
980 _rbcversion = b'-v1'
1075 _rbcversion = b'-v1'
981 _rbcnames = b'rbc-names' + _rbcversion
1076 _rbcnames = b'rbc-names' + _rbcversion
982 _rbcrevs = b'rbc-revs' + _rbcversion
1077 _rbcrevs = b'rbc-revs' + _rbcversion
983 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
1078 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
984 _rbcrecfmt = b'>4sI'
1079 _rbcrecfmt = b'>4sI'
985 _rbcrecsize = calcsize(_rbcrecfmt)
1080 _rbcrecsize = calcsize(_rbcrecfmt)
986 _rbcmininc = 64 * _rbcrecsize
1081 _rbcmininc = 64 * _rbcrecsize
987 _rbcnodelen = 4
1082 _rbcnodelen = 4
988 _rbcbranchidxmask = 0x7FFFFFFF
1083 _rbcbranchidxmask = 0x7FFFFFFF
989 _rbccloseflag = 0x80000000
1084 _rbccloseflag = 0x80000000
990
1085
991
1086
992 class rbcrevs:
1087 class rbcrevs:
993 """a byte string consisting of an immutable prefix followed by a mutable suffix"""
1088 """a byte string consisting of an immutable prefix followed by a mutable suffix"""
994
1089
995 def __init__(self, revs):
1090 def __init__(self, revs):
996 self._prefix = revs
1091 self._prefix = revs
997 self._rest = bytearray()
1092 self._rest = bytearray()
998
1093
999 def __len__(self):
1094 def __len__(self):
1000 return len(self._prefix) + len(self._rest)
1095 return len(self._prefix) + len(self._rest)
1001
1096
1002 def unpack_record(self, rbcrevidx):
1097 def unpack_record(self, rbcrevidx):
1003 if rbcrevidx < len(self._prefix):
1098 if rbcrevidx < len(self._prefix):
1004 return unpack_from(_rbcrecfmt, util.buffer(self._prefix), rbcrevidx)
1099 return unpack_from(_rbcrecfmt, util.buffer(self._prefix), rbcrevidx)
1005 else:
1100 else:
1006 return unpack_from(
1101 return unpack_from(
1007 _rbcrecfmt,
1102 _rbcrecfmt,
1008 util.buffer(self._rest),
1103 util.buffer(self._rest),
1009 rbcrevidx - len(self._prefix),
1104 rbcrevidx - len(self._prefix),
1010 )
1105 )
1011
1106
1012 def make_mutable(self):
1107 def make_mutable(self):
1013 if len(self._prefix) > 0:
1108 if len(self._prefix) > 0:
1014 entirety = bytearray()
1109 entirety = bytearray()
1015 entirety[:] = self._prefix
1110 entirety[:] = self._prefix
1016 entirety.extend(self._rest)
1111 entirety.extend(self._rest)
1017 self._rest = entirety
1112 self._rest = entirety
1018 self._prefix = bytearray()
1113 self._prefix = bytearray()
1019
1114
1020 def truncate(self, pos):
1115 def truncate(self, pos):
1021 self.make_mutable()
1116 self.make_mutable()
1022 del self._rest[pos:]
1117 del self._rest[pos:]
1023
1118
1024 def pack_into(self, rbcrevidx, node, branchidx):
1119 def pack_into(self, rbcrevidx, node, branchidx):
1025 if rbcrevidx < len(self._prefix):
1120 if rbcrevidx < len(self._prefix):
1026 self.make_mutable()
1121 self.make_mutable()
1027 buf = self._rest
1122 buf = self._rest
1028 start_offset = rbcrevidx - len(self._prefix)
1123 start_offset = rbcrevidx - len(self._prefix)
1029 end_offset = start_offset + _rbcrecsize
1124 end_offset = start_offset + _rbcrecsize
1030
1125
1031 if len(self._rest) < end_offset:
1126 if len(self._rest) < end_offset:
1032 # bytearray doesn't allocate extra space at least in Python 3.7.
1127 # bytearray doesn't allocate extra space at least in Python 3.7.
1033 # When multiple changesets are added in a row, precise resize would
1128 # When multiple changesets are added in a row, precise resize would
1034 # result in quadratic complexity. Overallocate to compensate by
1129 # result in quadratic complexity. Overallocate to compensate by
1035 # using the classic doubling technique for dynamic arrays instead.
1130 # using the classic doubling technique for dynamic arrays instead.
1036 # If there was a gap in the map before, less space will be reserved.
1131 # If there was a gap in the map before, less space will be reserved.
1037 self._rest.extend(b'\0' * end_offset)
1132 self._rest.extend(b'\0' * end_offset)
1038 return pack_into(
1133 return pack_into(
1039 _rbcrecfmt,
1134 _rbcrecfmt,
1040 buf,
1135 buf,
1041 start_offset,
1136 start_offset,
1042 node,
1137 node,
1043 branchidx,
1138 branchidx,
1044 )
1139 )
1045
1140
1046 def extend(self, extension):
1141 def extend(self, extension):
1047 return self._rest.extend(extension)
1142 return self._rest.extend(extension)
1048
1143
1049 def slice(self, begin, end):
1144 def slice(self, begin, end):
1050 if begin < len(self._prefix):
1145 if begin < len(self._prefix):
1051 acc = bytearray()
1146 acc = bytearray()
1052 acc[:] = self._prefix[begin:end]
1147 acc[:] = self._prefix[begin:end]
1053 acc.extend(
1148 acc.extend(
1054 self._rest[begin - len(self._prefix) : end - len(self._prefix)]
1149 self._rest[begin - len(self._prefix) : end - len(self._prefix)]
1055 )
1150 )
1056 return acc
1151 return acc
1057 return self._rest[begin - len(self._prefix) : end - len(self._prefix)]
1152 return self._rest[begin - len(self._prefix) : end - len(self._prefix)]
1058
1153
1059
1154
1060 class revbranchcache:
1155 class revbranchcache:
1061 """Persistent cache, mapping from revision number to branch name and close.
1156 """Persistent cache, mapping from revision number to branch name and close.
1062 This is a low level cache, independent of filtering.
1157 This is a low level cache, independent of filtering.
1063
1158
1064 Branch names are stored in rbc-names in internal encoding separated by 0.
1159 Branch names are stored in rbc-names in internal encoding separated by 0.
1065 rbc-names is append-only, and each branch name is only stored once and will
1160 rbc-names is append-only, and each branch name is only stored once and will
1066 thus have a unique index.
1161 thus have a unique index.
1067
1162
1068 The branch info for each revision is stored in rbc-revs as constant size
1163 The branch info for each revision is stored in rbc-revs as constant size
1069 records. The whole file is read into memory, but it is only 'parsed' on
1164 records. The whole file is read into memory, but it is only 'parsed' on
1070 demand. The file is usually append-only but will be truncated if repo
1165 demand. The file is usually append-only but will be truncated if repo
1071 modification is detected.
1166 modification is detected.
1072 The record for each revision contains the first 4 bytes of the
1167 The record for each revision contains the first 4 bytes of the
1073 corresponding node hash, and the record is only used if it still matches.
1168 corresponding node hash, and the record is only used if it still matches.
1074 Even a completely trashed rbc-revs fill thus still give the right result
1169 Even a completely trashed rbc-revs fill thus still give the right result
1075 while converging towards full recovery ... assuming no incorrectly matching
1170 while converging towards full recovery ... assuming no incorrectly matching
1076 node hashes.
1171 node hashes.
1077 The record also contains 4 bytes where 31 bits contains the index of the
1172 The record also contains 4 bytes where 31 bits contains the index of the
1078 branch and the last bit indicate that it is a branch close commit.
1173 branch and the last bit indicate that it is a branch close commit.
1079 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
1174 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
1080 and will grow with it but be 1/8th of its size.
1175 and will grow with it but be 1/8th of its size.
1081 """
1176 """
1082
1177
1083 def __init__(self, repo, readonly=True):
1178 def __init__(self, repo, readonly=True):
1084 assert repo.filtername is None
1179 assert repo.filtername is None
1085 self._repo = repo
1180 self._repo = repo
1086 self._names = [] # branch names in local encoding with static index
1181 self._names = [] # branch names in local encoding with static index
1087 self._rbcrevs = rbcrevs(bytearray())
1182 self._rbcrevs = rbcrevs(bytearray())
1088 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
1183 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
1089 try:
1184 try:
1090 bndata = repo.cachevfs.read(_rbcnames)
1185 bndata = repo.cachevfs.read(_rbcnames)
1091 self._rbcsnameslen = len(bndata) # for verification before writing
1186 self._rbcsnameslen = len(bndata) # for verification before writing
1092 if bndata:
1187 if bndata:
1093 self._names = [
1188 self._names = [
1094 encoding.tolocal(bn) for bn in bndata.split(b'\0')
1189 encoding.tolocal(bn) for bn in bndata.split(b'\0')
1095 ]
1190 ]
1096 except (IOError, OSError):
1191 except (IOError, OSError):
1097 if readonly:
1192 if readonly:
1098 # don't try to use cache - fall back to the slow path
1193 # don't try to use cache - fall back to the slow path
1099 self.branchinfo = self._branchinfo
1194 self.branchinfo = self._branchinfo
1100
1195
1101 if self._names:
1196 if self._names:
1102 try:
1197 try:
1103 if repo.ui.configbool(b'storage', b'revbranchcache.mmap'):
1198 if repo.ui.configbool(b'storage', b'revbranchcache.mmap'):
1104 with repo.cachevfs(_rbcrevs) as fp:
1199 with repo.cachevfs(_rbcrevs) as fp:
1105 data = util.buffer(util.mmapread(fp))
1200 data = util.buffer(util.mmapread(fp))
1106 else:
1201 else:
1107 data = repo.cachevfs.read(_rbcrevs)
1202 data = repo.cachevfs.read(_rbcrevs)
1108 self._rbcrevs = rbcrevs(data)
1203 self._rbcrevs = rbcrevs(data)
1109 except (IOError, OSError) as inst:
1204 except (IOError, OSError) as inst:
1110 repo.ui.debug(
1205 repo.ui.debug(
1111 b"couldn't read revision branch cache: %s\n"
1206 b"couldn't read revision branch cache: %s\n"
1112 % stringutil.forcebytestr(inst)
1207 % stringutil.forcebytestr(inst)
1113 )
1208 )
1114 # remember number of good records on disk
1209 # remember number of good records on disk
1115 self._rbcrevslen = min(
1210 self._rbcrevslen = min(
1116 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
1211 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
1117 )
1212 )
1118 if self._rbcrevslen == 0:
1213 if self._rbcrevslen == 0:
1119 self._names = []
1214 self._names = []
1120 self._rbcnamescount = len(self._names) # number of names read at
1215 self._rbcnamescount = len(self._names) # number of names read at
1121 # _rbcsnameslen
1216 # _rbcsnameslen
1122
1217
1123 def _clear(self):
1218 def _clear(self):
1124 self._rbcsnameslen = 0
1219 self._rbcsnameslen = 0
1125 del self._names[:]
1220 del self._names[:]
1126 self._rbcnamescount = 0
1221 self._rbcnamescount = 0
1127 self._rbcrevslen = len(self._repo.changelog)
1222 self._rbcrevslen = len(self._repo.changelog)
1128 self._rbcrevs = rbcrevs(bytearray(self._rbcrevslen * _rbcrecsize))
1223 self._rbcrevs = rbcrevs(bytearray(self._rbcrevslen * _rbcrecsize))
1129 util.clearcachedproperty(self, b'_namesreverse')
1224 util.clearcachedproperty(self, b'_namesreverse')
1130
1225
1131 @util.propertycache
1226 @util.propertycache
1132 def _namesreverse(self):
1227 def _namesreverse(self):
1133 return {b: r for r, b in enumerate(self._names)}
1228 return {b: r for r, b in enumerate(self._names)}
1134
1229
1135 def branchinfo(self, rev):
1230 def branchinfo(self, rev):
1136 """Return branch name and close flag for rev, using and updating
1231 """Return branch name and close flag for rev, using and updating
1137 persistent cache."""
1232 persistent cache."""
1138 changelog = self._repo.changelog
1233 changelog = self._repo.changelog
1139 rbcrevidx = rev * _rbcrecsize
1234 rbcrevidx = rev * _rbcrecsize
1140
1235
1141 # avoid negative index, changelog.read(nullrev) is fast without cache
1236 # avoid negative index, changelog.read(nullrev) is fast without cache
1142 if rev == nullrev:
1237 if rev == nullrev:
1143 return changelog.branchinfo(rev)
1238 return changelog.branchinfo(rev)
1144
1239
1145 # if requested rev isn't allocated, grow and cache the rev info
1240 # if requested rev isn't allocated, grow and cache the rev info
1146 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
1241 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
1147 return self._branchinfo(rev)
1242 return self._branchinfo(rev)
1148
1243
1149 # fast path: extract data from cache, use it if node is matching
1244 # fast path: extract data from cache, use it if node is matching
1150 reponode = changelog.node(rev)[:_rbcnodelen]
1245 reponode = changelog.node(rev)[:_rbcnodelen]
1151 cachenode, branchidx = self._rbcrevs.unpack_record(rbcrevidx)
1246 cachenode, branchidx = self._rbcrevs.unpack_record(rbcrevidx)
1152 close = bool(branchidx & _rbccloseflag)
1247 close = bool(branchidx & _rbccloseflag)
1153 if close:
1248 if close:
1154 branchidx &= _rbcbranchidxmask
1249 branchidx &= _rbcbranchidxmask
1155 if cachenode == b'\0\0\0\0':
1250 if cachenode == b'\0\0\0\0':
1156 pass
1251 pass
1157 elif cachenode == reponode:
1252 elif cachenode == reponode:
1158 try:
1253 try:
1159 return self._names[branchidx], close
1254 return self._names[branchidx], close
1160 except IndexError:
1255 except IndexError:
1161 # recover from invalid reference to unknown branch
1256 # recover from invalid reference to unknown branch
1162 self._repo.ui.debug(
1257 self._repo.ui.debug(
1163 b"referenced branch names not found"
1258 b"referenced branch names not found"
1164 b" - rebuilding revision branch cache from scratch\n"
1259 b" - rebuilding revision branch cache from scratch\n"
1165 )
1260 )
1166 self._clear()
1261 self._clear()
1167 else:
1262 else:
1168 # rev/node map has changed, invalidate the cache from here up
1263 # rev/node map has changed, invalidate the cache from here up
1169 self._repo.ui.debug(
1264 self._repo.ui.debug(
1170 b"history modification detected - truncating "
1265 b"history modification detected - truncating "
1171 b"revision branch cache to revision %d\n" % rev
1266 b"revision branch cache to revision %d\n" % rev
1172 )
1267 )
1173 truncate = rbcrevidx + _rbcrecsize
1268 truncate = rbcrevidx + _rbcrecsize
1174 self._rbcrevs.truncate(truncate)
1269 self._rbcrevs.truncate(truncate)
1175 self._rbcrevslen = min(self._rbcrevslen, truncate)
1270 self._rbcrevslen = min(self._rbcrevslen, truncate)
1176
1271
1177 # fall back to slow path and make sure it will be written to disk
1272 # fall back to slow path and make sure it will be written to disk
1178 return self._branchinfo(rev)
1273 return self._branchinfo(rev)
1179
1274
1180 def _branchinfo(self, rev):
1275 def _branchinfo(self, rev):
1181 """Retrieve branch info from changelog and update _rbcrevs"""
1276 """Retrieve branch info from changelog and update _rbcrevs"""
1182 changelog = self._repo.changelog
1277 changelog = self._repo.changelog
1183 b, close = changelog.branchinfo(rev)
1278 b, close = changelog.branchinfo(rev)
1184 if b in self._namesreverse:
1279 if b in self._namesreverse:
1185 branchidx = self._namesreverse[b]
1280 branchidx = self._namesreverse[b]
1186 else:
1281 else:
1187 branchidx = len(self._names)
1282 branchidx = len(self._names)
1188 self._names.append(b)
1283 self._names.append(b)
1189 self._namesreverse[b] = branchidx
1284 self._namesreverse[b] = branchidx
1190 reponode = changelog.node(rev)
1285 reponode = changelog.node(rev)
1191 if close:
1286 if close:
1192 branchidx |= _rbccloseflag
1287 branchidx |= _rbccloseflag
1193 self._setcachedata(rev, reponode, branchidx)
1288 self._setcachedata(rev, reponode, branchidx)
1194 return b, close
1289 return b, close
1195
1290
1196 def setdata(self, rev, changelogrevision):
1291 def setdata(self, rev, changelogrevision):
1197 """add new data information to the cache"""
1292 """add new data information to the cache"""
1198 branch, close = changelogrevision.branchinfo
1293 branch, close = changelogrevision.branchinfo
1199
1294
1200 if branch in self._namesreverse:
1295 if branch in self._namesreverse:
1201 branchidx = self._namesreverse[branch]
1296 branchidx = self._namesreverse[branch]
1202 else:
1297 else:
1203 branchidx = len(self._names)
1298 branchidx = len(self._names)
1204 self._names.append(branch)
1299 self._names.append(branch)
1205 self._namesreverse[branch] = branchidx
1300 self._namesreverse[branch] = branchidx
1206 if close:
1301 if close:
1207 branchidx |= _rbccloseflag
1302 branchidx |= _rbccloseflag
1208 self._setcachedata(rev, self._repo.changelog.node(rev), branchidx)
1303 self._setcachedata(rev, self._repo.changelog.node(rev), branchidx)
1209 # If no cache data were readable (non exists, bad permission, etc)
1304 # If no cache data were readable (non exists, bad permission, etc)
1210 # the cache was bypassing itself by setting:
1305 # the cache was bypassing itself by setting:
1211 #
1306 #
1212 # self.branchinfo = self._branchinfo
1307 # self.branchinfo = self._branchinfo
1213 #
1308 #
1214 # Since we now have data in the cache, we need to drop this bypassing.
1309 # Since we now have data in the cache, we need to drop this bypassing.
1215 if 'branchinfo' in vars(self):
1310 if 'branchinfo' in vars(self):
1216 del self.branchinfo
1311 del self.branchinfo
1217
1312
1218 def _setcachedata(self, rev, node, branchidx):
1313 def _setcachedata(self, rev, node, branchidx):
1219 """Writes the node's branch data to the in-memory cache data."""
1314 """Writes the node's branch data to the in-memory cache data."""
1220 if rev == nullrev:
1315 if rev == nullrev:
1221 return
1316 return
1222 rbcrevidx = rev * _rbcrecsize
1317 rbcrevidx = rev * _rbcrecsize
1223 self._rbcrevs.pack_into(rbcrevidx, node, branchidx)
1318 self._rbcrevs.pack_into(rbcrevidx, node, branchidx)
1224 self._rbcrevslen = min(self._rbcrevslen, rev)
1319 self._rbcrevslen = min(self._rbcrevslen, rev)
1225
1320
1226 tr = self._repo.currenttransaction()
1321 tr = self._repo.currenttransaction()
1227 if tr:
1322 if tr:
1228 tr.addfinalize(b'write-revbranchcache', self.write)
1323 tr.addfinalize(b'write-revbranchcache', self.write)
1229
1324
1230 def write(self, tr=None):
1325 def write(self, tr=None):
1231 """Save branch cache if it is dirty."""
1326 """Save branch cache if it is dirty."""
1232 repo = self._repo
1327 repo = self._repo
1233 wlock = None
1328 wlock = None
1234 step = b''
1329 step = b''
1235 try:
1330 try:
1236 # write the new names
1331 # write the new names
1237 if self._rbcnamescount < len(self._names):
1332 if self._rbcnamescount < len(self._names):
1238 wlock = repo.wlock(wait=False)
1333 wlock = repo.wlock(wait=False)
1239 step = b' names'
1334 step = b' names'
1240 self._writenames(repo)
1335 self._writenames(repo)
1241
1336
1242 # write the new revs
1337 # write the new revs
1243 start = self._rbcrevslen * _rbcrecsize
1338 start = self._rbcrevslen * _rbcrecsize
1244 if start != len(self._rbcrevs):
1339 if start != len(self._rbcrevs):
1245 step = b''
1340 step = b''
1246 if wlock is None:
1341 if wlock is None:
1247 wlock = repo.wlock(wait=False)
1342 wlock = repo.wlock(wait=False)
1248 self._writerevs(repo, start)
1343 self._writerevs(repo, start)
1249
1344
1250 except (IOError, OSError, error.Abort, error.LockError) as inst:
1345 except (IOError, OSError, error.Abort, error.LockError) as inst:
1251 repo.ui.debug(
1346 repo.ui.debug(
1252 b"couldn't write revision branch cache%s: %s\n"
1347 b"couldn't write revision branch cache%s: %s\n"
1253 % (step, stringutil.forcebytestr(inst))
1348 % (step, stringutil.forcebytestr(inst))
1254 )
1349 )
1255 finally:
1350 finally:
1256 if wlock is not None:
1351 if wlock is not None:
1257 wlock.release()
1352 wlock.release()
1258
1353
1259 def _writenames(self, repo):
1354 def _writenames(self, repo):
1260 """write the new branch names to revbranchcache"""
1355 """write the new branch names to revbranchcache"""
1261 if self._rbcnamescount != 0:
1356 if self._rbcnamescount != 0:
1262 f = repo.cachevfs.open(_rbcnames, b'ab')
1357 f = repo.cachevfs.open(_rbcnames, b'ab')
1263 if f.tell() == self._rbcsnameslen:
1358 if f.tell() == self._rbcsnameslen:
1264 f.write(b'\0')
1359 f.write(b'\0')
1265 else:
1360 else:
1266 f.close()
1361 f.close()
1267 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames)
1362 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames)
1268 self._rbcnamescount = 0
1363 self._rbcnamescount = 0
1269 self._rbcrevslen = 0
1364 self._rbcrevslen = 0
1270 if self._rbcnamescount == 0:
1365 if self._rbcnamescount == 0:
1271 # before rewriting names, make sure references are removed
1366 # before rewriting names, make sure references are removed
1272 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
1367 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
1273 f = repo.cachevfs.open(_rbcnames, b'wb')
1368 f = repo.cachevfs.open(_rbcnames, b'wb')
1274 f.write(
1369 f.write(
1275 b'\0'.join(
1370 b'\0'.join(
1276 encoding.fromlocal(b)
1371 encoding.fromlocal(b)
1277 for b in self._names[self._rbcnamescount :]
1372 for b in self._names[self._rbcnamescount :]
1278 )
1373 )
1279 )
1374 )
1280 self._rbcsnameslen = f.tell()
1375 self._rbcsnameslen = f.tell()
1281 f.close()
1376 f.close()
1282 self._rbcnamescount = len(self._names)
1377 self._rbcnamescount = len(self._names)
1283
1378
1284 def _writerevs(self, repo, start):
1379 def _writerevs(self, repo, start):
1285 """write the new revs to revbranchcache"""
1380 """write the new revs to revbranchcache"""
1286 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
1381 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
1287 with repo.cachevfs.open(_rbcrevs, b'ab') as f:
1382 with repo.cachevfs.open(_rbcrevs, b'ab') as f:
1288 if f.tell() != start:
1383 if f.tell() != start:
1289 repo.ui.debug(
1384 repo.ui.debug(
1290 b"truncating cache/%s to %d\n" % (_rbcrevs, start)
1385 b"truncating cache/%s to %d\n" % (_rbcrevs, start)
1291 )
1386 )
1292 f.seek(start)
1387 f.seek(start)
1293 if f.tell() != start:
1388 if f.tell() != start:
1294 start = 0
1389 start = 0
1295 f.seek(start)
1390 f.seek(start)
1296 f.truncate()
1391 f.truncate()
1297 end = revs * _rbcrecsize
1392 end = revs * _rbcrecsize
1298 f.write(self._rbcrevs.slice(start, end))
1393 f.write(self._rbcrevs.slice(start, end))
1299 self._rbcrevslen = revs
1394 self._rbcrevslen = revs
@@ -1,546 +1,563 b''
1 ================================================================
1 ================================================================
2 test the interaction of the branch cache with obsolete changeset
2 test the interaction of the branch cache with obsolete changeset
3 ================================================================
3 ================================================================
4
4
5 Some corner case have been covered by unrelated test (like rebase ones) this
5 Some corner case have been covered by unrelated test (like rebase ones) this
6 file meant to gather explicite testing of those.
6 file meant to gather explicite testing of those.
7
7
8 See also: test-obsolete-checkheads.t
8 See also: test-obsolete-checkheads.t
9
9
10 #testcases v2 v3
10 #testcases v2 v3
11
11
12 $ cat >> $HGRCPATH << EOF
12 $ cat >> $HGRCPATH << EOF
13 > [phases]
13 > [phases]
14 > publish = false
14 > publish = false
15 > [experimental]
15 > [experimental]
16 > evolution = all
16 > evolution = all
17 > server.allow-hidden-access = *
17 > server.allow-hidden-access = *
18 > EOF
18 > EOF
19
19
20 #if v3
20 #if v3
21 $ cat <<EOF >> $HGRCPATH
21 $ cat <<EOF >> $HGRCPATH
22 > [experimental]
22 > [experimental]
23 > branch-cache-v3=yes
23 > branch-cache-v3=yes
24 > EOF
24 > EOF
25 $ CACHE_PREFIX=branch3
25 $ CACHE_PREFIX=branch3
26 #else
26 #else
27 $ cat <<EOF >> $HGRCPATH
27 $ cat <<EOF >> $HGRCPATH
28 > [experimental]
28 > [experimental]
29 > branch-cache-v3=no
29 > branch-cache-v3=no
30 > EOF
30 > EOF
31 $ CACHE_PREFIX=branch2
31 $ CACHE_PREFIX=branch2
32 #endif
32 #endif
33
33
34 $ show_cache() {
34 $ show_cache() {
35 > for cache_file in .hg/cache/$CACHE_PREFIX*; do
35 > for cache_file in .hg/cache/$CACHE_PREFIX*; do
36 > echo "##### $cache_file"
36 > echo "##### $cache_file"
37 > cat $cache_file
37 > cat $cache_file
38 > done
38 > done
39 > }
39 > }
40
40
41 Setup graph
41 Setup graph
42 #############
42 #############
43
43
44 $ . $RUNTESTDIR/testlib/common.sh
44 $ . $RUNTESTDIR/testlib/common.sh
45
45
46 graph with a single branch
46 graph with a single branch
47 --------------------------
47 --------------------------
48
48
49 We want some branching and some obsolescence
49 We want some branching and some obsolescence
50
50
51 $ hg init main-single-branch
51 $ hg init main-single-branch
52 $ cd main-single-branch
52 $ cd main-single-branch
53 $ mkcommit root
53 $ mkcommit root
54 $ mkcommit A_1
54 $ mkcommit A_1
55 $ mkcommit A_2
55 $ mkcommit A_2
56 $ hg update 'desc("A_2")' --quiet
56 $ hg update 'desc("A_2")' --quiet
57 $ mkcommit B_1
57 $ mkcommit B_1
58 $ mkcommit B_2
58 $ mkcommit B_2
59 $ mkcommit B_3
59 $ mkcommit B_3
60 $ mkcommit B_4
60 $ mkcommit B_4
61 $ hg update 'desc("A_2")' --quiet
61 $ hg update 'desc("A_2")' --quiet
62 $ mkcommit A_3
62 $ mkcommit A_3
63 created new head
63 created new head
64 $ mkcommit A_4
64 $ mkcommit A_4
65 $ hg up null --quiet
65 $ hg up null --quiet
66 $ hg clone --noupdate . ../main-single-branch-pre-ops
66 $ hg clone --noupdate . ../main-single-branch-pre-ops
67 $ hg log -r 'desc("A_1")' -T '{node}' > ../main-single-branch-node_A1
67 $ hg log -r 'desc("A_1")' -T '{node}' > ../main-single-branch-node_A1
68 $ hg log -r 'desc("A_2")' -T '{node}' > ../main-single-branch-node_A2
68 $ hg log -r 'desc("A_2")' -T '{node}' > ../main-single-branch-node_A2
69 $ hg log -r 'desc("A_3")' -T '{node}' > ../main-single-branch-node_A3
69 $ hg log -r 'desc("A_3")' -T '{node}' > ../main-single-branch-node_A3
70 $ hg log -r 'desc("A_4")' -T '{node}' > ../main-single-branch-node_A4
70 $ hg log -r 'desc("A_4")' -T '{node}' > ../main-single-branch-node_A4
71 $ hg log -r 'desc("B_1")' -T '{node}' > ../main-single-branch-node_B1
71 $ hg log -r 'desc("B_1")' -T '{node}' > ../main-single-branch-node_B1
72 $ hg log -r 'desc("B_2")' -T '{node}' > ../main-single-branch-node_B2
72 $ hg log -r 'desc("B_2")' -T '{node}' > ../main-single-branch-node_B2
73 $ hg log -r 'desc("B_3")' -T '{node}' > ../main-single-branch-node_B3
73 $ hg log -r 'desc("B_3")' -T '{node}' > ../main-single-branch-node_B3
74 $ hg log -r 'desc("B_4")' -T '{node}' > ../main-single-branch-node_B4
74 $ hg log -r 'desc("B_4")' -T '{node}' > ../main-single-branch-node_B4
75
75
76 (double check the heads are right before we obsolete)
76 (double check the heads are right before we obsolete)
77
77
78 $ hg log -R ../main-single-branch-pre-ops -G -T '{desc}\n'
78 $ hg log -R ../main-single-branch-pre-ops -G -T '{desc}\n'
79 o A_4
79 o A_4
80 |
80 |
81 o A_3
81 o A_3
82 |
82 |
83 | o B_4
83 | o B_4
84 | |
84 | |
85 | o B_3
85 | o B_3
86 | |
86 | |
87 | o B_2
87 | o B_2
88 | |
88 | |
89 | o B_1
89 | o B_1
90 |/
90 |/
91 o A_2
91 o A_2
92 |
92 |
93 o A_1
93 o A_1
94 |
94 |
95 o root
95 o root
96
96
97 $ hg log -G -T '{desc}\n'
97 $ hg log -G -T '{desc}\n'
98 o A_4
98 o A_4
99 |
99 |
100 o A_3
100 o A_3
101 |
101 |
102 | o B_4
102 | o B_4
103 | |
103 | |
104 | o B_3
104 | o B_3
105 | |
105 | |
106 | o B_2
106 | o B_2
107 | |
107 | |
108 | o B_1
108 | o B_1
109 |/
109 |/
110 o A_2
110 o A_2
111 |
111 |
112 o A_1
112 o A_1
113 |
113 |
114 o root
114 o root
115
115
116
117 #if v2
118 $ show_cache
119 ##### .hg/cache/branch2-served
120 3d808bbc94408ea19da905596d4079357a1f28be 8
121 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
122 3d808bbc94408ea19da905596d4079357a1f28be o default
123 #else
124 $ show_cache
125 ##### .hg/cache/branch3-served
126 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8 topo-mode=pure
127 default
128 #endif
116 $ hg log -T '{desc}\n' --rev 'head()'
129 $ hg log -T '{desc}\n' --rev 'head()'
117 B_4
130 B_4
118 A_4
131 A_4
119
132
120 Absolete a couple of changes
133 Absolete a couple of changes
121
134
122 $ for d in B2 B3 B4 A4; do
135 $ for d in B2 B3 B4 A4; do
123 > hg debugobsolete --record-parents `cat ../main-single-branch-node_$d`;
136 > hg debugobsolete --record-parents `cat ../main-single-branch-node_$d`;
124 > done
137 > done
125 1 new obsolescence markers
138 1 new obsolescence markers
126 obsoleted 1 changesets
139 obsoleted 1 changesets
127 2 new orphan changesets
140 2 new orphan changesets
128 1 new obsolescence markers
141 1 new obsolescence markers
129 obsoleted 1 changesets
142 obsoleted 1 changesets
130 1 new obsolescence markers
143 1 new obsolescence markers
131 obsoleted 1 changesets
144 obsoleted 1 changesets
132 1 new obsolescence markers
145 1 new obsolescence markers
133 obsoleted 1 changesets
146 obsoleted 1 changesets
134
147
135 (double check the result is okay)
148 (double check the result is okay)
136
149
137 $ hg log -G -T '{desc}\n'
150 $ hg log -G -T '{desc}\n'
138 o A_3
151 o A_3
139 |
152 |
140 | o B_1
153 | o B_1
141 |/
154 |/
142 o A_2
155 o A_2
143 |
156 |
144 o A_1
157 o A_1
145 |
158 |
146 o root
159 o root
147
160
148 $ hg heads -T '{desc}\n'
161 $ hg heads -T '{desc}\n'
149 A_3
162 A_3
150 B_1
163 B_1
151 #if v2
164 #if v2
152 $ show_cache
165 $ show_cache
153 ##### .hg/cache/branch2-served
166 ##### .hg/cache/branch2-served
154 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
167 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
155 550bb31f072912453ccbb503de1d554616911e88 o default
168 550bb31f072912453ccbb503de1d554616911e88 o default
156 7c29ff2453bf38c75ee8982935739103c38a9284 o default
169 7c29ff2453bf38c75ee8982935739103c38a9284 o default
157 #else
170 #else
158 $ show_cache
171 $ show_cache
159 ##### .hg/cache/branch3-served
172 ##### .hg/cache/branch3-served
160 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
173 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7 topo-mode=pure
174 default
161 #endif
175 #endif
162 $ cd ..
176 $ cd ..
163
177
164
178
165 Actual testing
179 Actual testing
166 ##############
180 ##############
167
181
168 Revealing obsolete changeset
182 Revealing obsolete changeset
169 ----------------------------
183 ----------------------------
170
184
171 Check that revealing obsolete changesets does not confuse branch computation and checks
185 Check that revealing obsolete changesets does not confuse branch computation and checks
172
186
173 Revealing tipmost changeset
187 Revealing tipmost changeset
174 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
188 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
175
189
176
190
177 $ cp -R ./main-single-branch tmp-repo
191 $ cp -R ./main-single-branch tmp-repo
178 $ cd tmp-repo
192 $ cd tmp-repo
179 $ hg update --hidden --rev 'desc("A_4")' --quiet
193 $ hg update --hidden --rev 'desc("A_4")' --quiet
180 updated to hidden changeset 3d808bbc9440
194 updated to hidden changeset 3d808bbc9440
181 (hidden revision '3d808bbc9440' is pruned)
195 (hidden revision '3d808bbc9440' is pruned)
182 $ hg log -G -T '{desc}\n'
196 $ hg log -G -T '{desc}\n'
183 @ A_4
197 @ A_4
184 |
198 |
185 o A_3
199 o A_3
186 |
200 |
187 | o B_1
201 | o B_1
188 |/
202 |/
189 o A_2
203 o A_2
190 |
204 |
191 o A_1
205 o A_1
192 |
206 |
193 o root
207 o root
194
208
195 $ hg heads -T '{desc}\n'
209 $ hg heads -T '{desc}\n'
196 A_3
210 A_3
197 B_1
211 B_1
198 #if v2
212 #if v2
199 $ show_cache
213 $ show_cache
200 ##### .hg/cache/branch2
214 ##### .hg/cache/branch2
201 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
215 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
202 550bb31f072912453ccbb503de1d554616911e88 o default
216 550bb31f072912453ccbb503de1d554616911e88 o default
203 7c29ff2453bf38c75ee8982935739103c38a9284 o default
217 7c29ff2453bf38c75ee8982935739103c38a9284 o default
204 ##### .hg/cache/branch2-served
218 ##### .hg/cache/branch2-served
205 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
219 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
206 550bb31f072912453ccbb503de1d554616911e88 o default
220 550bb31f072912453ccbb503de1d554616911e88 o default
207 7c29ff2453bf38c75ee8982935739103c38a9284 o default
221 7c29ff2453bf38c75ee8982935739103c38a9284 o default
208 #else
222 #else
209 $ show_cache
223 $ show_cache
210 ##### .hg/cache/branch3
224 ##### .hg/cache/branch3
211 obsolete-hash=b6d2b1f5b70f09c25c835edcae69be35f681605c tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
225 obsolete-hash=b6d2b1f5b70f09c25c835edcae69be35f681605c tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
212 550bb31f072912453ccbb503de1d554616911e88 o default
213 7c29ff2453bf38c75ee8982935739103c38a9284 o default
226 7c29ff2453bf38c75ee8982935739103c38a9284 o default
214 ##### .hg/cache/branch3-served
227 ##### .hg/cache/branch3-served
215 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
228 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
216 7c29ff2453bf38c75ee8982935739103c38a9284 o default
229 7c29ff2453bf38c75ee8982935739103c38a9284 o default
217 #endif
230 #endif
218
231
219 Even when computing branches from scratch
232 Even when computing branches from scratch
220
233
221 $ rm -rf .hg/cache/branch*
234 $ rm -rf .hg/cache/branch*
222 $ rm -rf .hg/wcache/branch*
235 $ rm -rf .hg/wcache/branch*
223 $ hg heads -T '{desc}\n'
236 $ hg heads -T '{desc}\n'
224 A_3
237 A_3
225 B_1
238 B_1
226 #if v2
239 #if v2
227 $ show_cache
240 $ show_cache
228 ##### .hg/cache/branch2-served
241 ##### .hg/cache/branch2-served
229 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
242 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
230 550bb31f072912453ccbb503de1d554616911e88 o default
243 550bb31f072912453ccbb503de1d554616911e88 o default
231 7c29ff2453bf38c75ee8982935739103c38a9284 o default
244 7c29ff2453bf38c75ee8982935739103c38a9284 o default
232 #else
245 #else
233 $ show_cache
246 $ show_cache
234 ##### .hg/cache/branch3-served
247 ##### .hg/cache/branch3-served
235 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
248 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
236 7c29ff2453bf38c75ee8982935739103c38a9284 o default
249 7c29ff2453bf38c75ee8982935739103c38a9284 o default
237 #endif
250 #endif
238
251
239 And we can get back to normal
252 And we can get back to normal
240
253
241 $ hg update null --quiet
254 $ hg update null --quiet
242 $ hg heads -T '{desc}\n'
255 $ hg heads -T '{desc}\n'
243 A_3
256 A_3
244 B_1
257 B_1
245 #if v2
258 #if v2
246 $ show_cache
259 $ show_cache
247 ##### .hg/cache/branch2-served
260 ##### .hg/cache/branch2-served
248 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
261 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
249 550bb31f072912453ccbb503de1d554616911e88 o default
262 550bb31f072912453ccbb503de1d554616911e88 o default
250 7c29ff2453bf38c75ee8982935739103c38a9284 o default
263 7c29ff2453bf38c75ee8982935739103c38a9284 o default
251 #else
264 #else
252 $ show_cache
265 $ show_cache
253 ##### .hg/cache/branch3-served
266 ##### .hg/cache/branch3-served
254 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
267 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7 topo-mode=pure
268 default
255 #endif
269 #endif
256
270
257 $ cd ..
271 $ cd ..
258 $ rm -rf tmp-repo
272 $ rm -rf tmp-repo
259
273
260 Revealing changeset in the middle of the changelog
274 Revealing changeset in the middle of the changelog
261 ~~~~~~~~~~~~~~~~~~~~~~~~~~~------------------------
275 ~~~~~~~~~~~~~~~~~~~~~~~~~~~------------------------
262
276
263 Check that revealing an obsolete changeset does not confuse branch computation and checks
277 Check that revealing an obsolete changeset does not confuse branch computation and checks
264
278
265 $ cp -R ./main-single-branch tmp-repo
279 $ cp -R ./main-single-branch tmp-repo
266 $ cd tmp-repo
280 $ cd tmp-repo
267 $ hg update --hidden --rev 'desc("B_3")' --quiet
281 $ hg update --hidden --rev 'desc("B_3")' --quiet
268 updated to hidden changeset 9c996d7674bb
282 updated to hidden changeset 9c996d7674bb
269 (hidden revision '9c996d7674bb' is pruned)
283 (hidden revision '9c996d7674bb' is pruned)
270 $ hg log -G -T '{desc}\n'
284 $ hg log -G -T '{desc}\n'
271 o A_3
285 o A_3
272 |
286 |
273 | @ B_3
287 | @ B_3
274 | |
288 | |
275 | x B_2
289 | x B_2
276 | |
290 | |
277 | o B_1
291 | o B_1
278 |/
292 |/
279 o A_2
293 o A_2
280 |
294 |
281 o A_1
295 o A_1
282 |
296 |
283 o root
297 o root
284
298
285 $ hg heads -T '{desc}\n'
299 $ hg heads -T '{desc}\n'
286 A_3
300 A_3
287 B_1
301 B_1
288 #if v2
302 #if v2
289 $ show_cache
303 $ show_cache
290 ##### .hg/cache/branch2
304 ##### .hg/cache/branch2
291 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
305 3d808bbc94408ea19da905596d4079357a1f28be 8 a943c3355ad9e93654d58b1c934c7c4329a5d1d4
292 550bb31f072912453ccbb503de1d554616911e88 o default
306 550bb31f072912453ccbb503de1d554616911e88 o default
293 7c29ff2453bf38c75ee8982935739103c38a9284 o default
307 7c29ff2453bf38c75ee8982935739103c38a9284 o default
294 ##### .hg/cache/branch2-served
308 ##### .hg/cache/branch2-served
295 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
309 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
296 550bb31f072912453ccbb503de1d554616911e88 o default
310 550bb31f072912453ccbb503de1d554616911e88 o default
297 7c29ff2453bf38c75ee8982935739103c38a9284 o default
311 7c29ff2453bf38c75ee8982935739103c38a9284 o default
298 #else
312 #else
299 $ show_cache
313 $ show_cache
300 ##### .hg/cache/branch3
314 ##### .hg/cache/branch3
301 obsolete-hash=b6d2b1f5b70f09c25c835edcae69be35f681605c tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
315 obsolete-hash=b6d2b1f5b70f09c25c835edcae69be35f681605c tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
302 550bb31f072912453ccbb503de1d554616911e88 o default
303 7c29ff2453bf38c75ee8982935739103c38a9284 o default
316 7c29ff2453bf38c75ee8982935739103c38a9284 o default
304 ##### .hg/cache/branch3-served
317 ##### .hg/cache/branch3-served
305 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
318 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
306 550bb31f072912453ccbb503de1d554616911e88 o default
319 550bb31f072912453ccbb503de1d554616911e88 o default
307 #endif
320 #endif
308
321
309 Even when computing branches from scratch
322 Even when computing branches from scratch
310
323
311 $ rm -rf .hg/cache/branch*
324 $ rm -rf .hg/cache/branch*
312 $ rm -rf .hg/wcache/branch*
325 $ rm -rf .hg/wcache/branch*
313 $ hg heads -T '{desc}\n'
326 $ hg heads -T '{desc}\n'
314 A_3
327 A_3
315 B_1
328 B_1
316 #if v2
329 #if v2
317 $ show_cache
330 $ show_cache
318 ##### .hg/cache/branch2-served
331 ##### .hg/cache/branch2-served
319 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
332 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
320 550bb31f072912453ccbb503de1d554616911e88 o default
333 550bb31f072912453ccbb503de1d554616911e88 o default
321 7c29ff2453bf38c75ee8982935739103c38a9284 o default
334 7c29ff2453bf38c75ee8982935739103c38a9284 o default
322 #else
335 #else
323 $ show_cache
336 $ show_cache
324 ##### .hg/cache/branch3-served
337 ##### .hg/cache/branch3-served
325 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
338 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
326 550bb31f072912453ccbb503de1d554616911e88 o default
339 550bb31f072912453ccbb503de1d554616911e88 o default
327 #endif
340 #endif
328
341
329 And we can get back to normal
342 And we can get back to normal
330
343
331 $ hg update null --quiet
344 $ hg update null --quiet
332 $ hg heads -T '{desc}\n'
345 $ hg heads -T '{desc}\n'
333 A_3
346 A_3
334 B_1
347 B_1
335 #if v2
348 #if v2
336 $ show_cache
349 $ show_cache
337 ##### .hg/cache/branch2-served
350 ##### .hg/cache/branch2-served
338 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
351 7c29ff2453bf38c75ee8982935739103c38a9284 7 f8006d64a10d35c011a5c5fa88be1e25c5929514
339 550bb31f072912453ccbb503de1d554616911e88 o default
352 550bb31f072912453ccbb503de1d554616911e88 o default
340 7c29ff2453bf38c75ee8982935739103c38a9284 o default
353 7c29ff2453bf38c75ee8982935739103c38a9284 o default
341 #else
354 #else
342 $ show_cache
355 $ show_cache
343 ##### .hg/cache/branch3-served
356 ##### .hg/cache/branch3-served
344 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
357 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7 topo-mode=pure
358 default
345 #endif
359 #endif
346
360
347 $ cd ..
361 $ cd ..
348 $ rm -rf tmp-repo
362 $ rm -rf tmp-repo
349
363
350 Getting the obsolescence marker after the fact for the tip rev
364 Getting the obsolescence marker after the fact for the tip rev
351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
365 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352
366
353 $ cp -R ./main-single-branch-pre-ops tmp-repo
367 $ cp -R ./main-single-branch-pre-ops tmp-repo
354 $ cd tmp-repo
368 $ cd tmp-repo
355 $ hg update --hidden --rev 'desc("A_4")' --quiet
369 $ hg update --hidden --rev 'desc("A_4")' --quiet
356 $ hg log -G -T '{desc}\n'
370 $ hg log -G -T '{desc}\n'
357 @ A_4
371 @ A_4
358 |
372 |
359 o A_3
373 o A_3
360 |
374 |
361 | o B_4
375 | o B_4
362 | |
376 | |
363 | o B_3
377 | o B_3
364 | |
378 | |
365 | o B_2
379 | o B_2
366 | |
380 | |
367 | o B_1
381 | o B_1
368 |/
382 |/
369 o A_2
383 o A_2
370 |
384 |
371 o A_1
385 o A_1
372 |
386 |
373 o root
387 o root
374
388
375 $ hg heads -T '{desc}\n'
389 $ hg heads -T '{desc}\n'
376 A_4
390 A_4
377 B_4
391 B_4
378 $ hg pull --rev `cat ../main-single-branch-node_A4` --remote-hidden
392 $ hg pull --rev `cat ../main-single-branch-node_A4` --remote-hidden
379 pulling from $TESTTMP/main-single-branch
393 pulling from $TESTTMP/main-single-branch
380 no changes found
394 no changes found
381 1 new obsolescence markers
395 1 new obsolescence markers
382 obsoleted 1 changesets
396 obsoleted 1 changesets
383
397
384 branch head are okay
398 branch head are okay
385
399
386 $ hg heads -T '{desc}\n'
400 $ hg heads -T '{desc}\n'
387 A_3
401 A_3
388 B_4
402 B_4
389 #if v2
403 #if v2
390 $ show_cache
404 $ show_cache
391 ##### .hg/cache/branch2-served
405 ##### .hg/cache/branch2-served
392 3d808bbc94408ea19da905596d4079357a1f28be 8 ac5282439f301518f362f37547fcd52bcc670373
406 3d808bbc94408ea19da905596d4079357a1f28be 8 ac5282439f301518f362f37547fcd52bcc670373
393 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
407 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
394 7c29ff2453bf38c75ee8982935739103c38a9284 o default
408 7c29ff2453bf38c75ee8982935739103c38a9284 o default
395 #else
409 #else
396 $ show_cache
410 $ show_cache
397 ##### .hg/cache/branch3-served
411 ##### .hg/cache/branch3-served
398 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
412 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
399 7c29ff2453bf38c75ee8982935739103c38a9284 o default
413 7c29ff2453bf38c75ee8982935739103c38a9284 o default
400 #endif
414 #endif
401
415
402 Even when computing branches from scratch
416 Even when computing branches from scratch
403
417
404 $ rm -rf .hg/cache/branch*
418 $ rm -rf .hg/cache/branch*
405 $ rm -rf .hg/wcache/branch*
419 $ rm -rf .hg/wcache/branch*
406 $ hg heads -T '{desc}\n'
420 $ hg heads -T '{desc}\n'
407 A_3
421 A_3
408 B_4
422 B_4
409 #if v2
423 #if v2
410 $ show_cache
424 $ show_cache
411 ##### .hg/cache/branch2-served
425 ##### .hg/cache/branch2-served
412 3d808bbc94408ea19da905596d4079357a1f28be 8 ac5282439f301518f362f37547fcd52bcc670373
426 3d808bbc94408ea19da905596d4079357a1f28be 8 ac5282439f301518f362f37547fcd52bcc670373
413 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
427 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
414 7c29ff2453bf38c75ee8982935739103c38a9284 o default
428 7c29ff2453bf38c75ee8982935739103c38a9284 o default
415 #else
429 #else
416 $ show_cache
430 $ show_cache
417 ##### .hg/cache/branch3-served
431 ##### .hg/cache/branch3-served
418 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
432 obsolete-hash=ac5282439f301518f362f37547fcd52bcc670373 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
419 7c29ff2453bf38c75ee8982935739103c38a9284 o default
433 7c29ff2453bf38c75ee8982935739103c38a9284 o default
420 #endif
434 #endif
421
435
422 And we can get back to normal
436 And we can get back to normal
423
437
424 $ hg update null --quiet
438 $ hg update null --quiet
425 $ hg heads -T '{desc}\n'
439 $ hg heads -T '{desc}\n'
426 A_3
440 A_3
427 B_4
441 B_4
428 #if v2
442 #if v2
429 $ show_cache
443 $ show_cache
430 ##### .hg/cache/branch2-served
444 ##### .hg/cache/branch2-served
431 7c29ff2453bf38c75ee8982935739103c38a9284 7
445 7c29ff2453bf38c75ee8982935739103c38a9284 7
432 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
446 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
433 7c29ff2453bf38c75ee8982935739103c38a9284 o default
447 7c29ff2453bf38c75ee8982935739103c38a9284 o default
434 #else
448 #else
435 $ show_cache
449 $ show_cache
436 ##### .hg/cache/branch3-served
450 ##### .hg/cache/branch3-served
437 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7
451 tip-node=7c29ff2453bf38c75ee8982935739103c38a9284 tip-rev=7 topo-mode=pure
452 default
438 #endif
453 #endif
439
454
440 $ cd ..
455 $ cd ..
441 $ rm -rf tmp-repo
456 $ rm -rf tmp-repo
442
457
443 Getting the obsolescence marker after the fact for another rev
458 Getting the obsolescence marker after the fact for another rev
444 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
459 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
445
460
446 $ cp -R ./main-single-branch-pre-ops tmp-repo
461 $ cp -R ./main-single-branch-pre-ops tmp-repo
447 $ cd tmp-repo
462 $ cd tmp-repo
448 $ hg update --hidden --rev 'desc("B_3")' --quiet
463 $ hg update --hidden --rev 'desc("B_3")' --quiet
449 $ hg log -G -T '{desc}\n'
464 $ hg log -G -T '{desc}\n'
450 o A_4
465 o A_4
451 |
466 |
452 o A_3
467 o A_3
453 |
468 |
454 | o B_4
469 | o B_4
455 | |
470 | |
456 | @ B_3
471 | @ B_3
457 | |
472 | |
458 | o B_2
473 | o B_2
459 | |
474 | |
460 | o B_1
475 | o B_1
461 |/
476 |/
462 o A_2
477 o A_2
463 |
478 |
464 o A_1
479 o A_1
465 |
480 |
466 o root
481 o root
467
482
468 $ hg heads -T '{desc}\n'
483 $ hg heads -T '{desc}\n'
469 A_4
484 A_4
470 B_4
485 B_4
471 #if v2
486 #if v2
472 $ show_cache
487 $ show_cache
473 ##### .hg/cache/branch2-served
488 ##### .hg/cache/branch2-served
474 3d808bbc94408ea19da905596d4079357a1f28be 8
489 3d808bbc94408ea19da905596d4079357a1f28be 8
475 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
490 63ba7cd843d1e95aac1a24435befeb1909c53619 o default
476 3d808bbc94408ea19da905596d4079357a1f28be o default
491 3d808bbc94408ea19da905596d4079357a1f28be o default
477 #else
492 #else
478 $ show_cache
493 $ show_cache
479 ##### .hg/cache/branch3-served
494 ##### .hg/cache/branch3-served
480 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
495 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8 topo-mode=pure
496 default
481 #endif
497 #endif
482
498
483 $ hg pull --rev `cat ../main-single-branch-node_B4` --remote-hidden
499 $ hg pull --rev `cat ../main-single-branch-node_B4` --remote-hidden
484 pulling from $TESTTMP/main-single-branch
500 pulling from $TESTTMP/main-single-branch
485 no changes found
501 no changes found
486 3 new obsolescence markers
502 3 new obsolescence markers
487 obsoleted 3 changesets
503 obsoleted 3 changesets
488
504
489 branch head are okay
505 branch head are okay
490
506
491 $ hg heads -T '{desc}\n'
507 $ hg heads -T '{desc}\n'
492 A_4
508 A_4
493 B_1
509 B_1
494 #if v2
510 #if v2
495 $ show_cache
511 $ show_cache
496 ##### .hg/cache/branch2-served
512 ##### .hg/cache/branch2-served
497 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
513 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
498 550bb31f072912453ccbb503de1d554616911e88 o default
514 550bb31f072912453ccbb503de1d554616911e88 o default
499 3d808bbc94408ea19da905596d4079357a1f28be o default
515 3d808bbc94408ea19da905596d4079357a1f28be o default
500 #else
516 #else
501 $ show_cache
517 $ show_cache
502 ##### .hg/cache/branch3-served
518 ##### .hg/cache/branch3-served
503 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
519 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
504 550bb31f072912453ccbb503de1d554616911e88 o default
520 550bb31f072912453ccbb503de1d554616911e88 o default
505 #endif
521 #endif
506
522
507 Even when computing branches from scratch
523 Even when computing branches from scratch
508
524
509 $ rm -rf .hg/cache/branch*
525 $ rm -rf .hg/cache/branch*
510 $ rm -rf .hg/wcache/branch*
526 $ rm -rf .hg/wcache/branch*
511 $ hg heads -T '{desc}\n'
527 $ hg heads -T '{desc}\n'
512 A_4
528 A_4
513 B_1
529 B_1
514 #if v2
530 #if v2
515 $ show_cache
531 $ show_cache
516 ##### .hg/cache/branch2-served
532 ##### .hg/cache/branch2-served
517 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
533 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
518 550bb31f072912453ccbb503de1d554616911e88 o default
534 550bb31f072912453ccbb503de1d554616911e88 o default
519 3d808bbc94408ea19da905596d4079357a1f28be o default
535 3d808bbc94408ea19da905596d4079357a1f28be o default
520 #else
536 #else
521 $ show_cache
537 $ show_cache
522 ##### .hg/cache/branch3-served
538 ##### .hg/cache/branch3-served
523 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
539 filtered-hash=f1456c0d675980582dda9b8edc7f13f503ce544f obsolete-hash=3e74f5349008671629e39d13d7e00d9ba94c74f7 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
524 550bb31f072912453ccbb503de1d554616911e88 o default
540 550bb31f072912453ccbb503de1d554616911e88 o default
525 #endif
541 #endif
526
542
527 And we can get back to normal
543 And we can get back to normal
528
544
529 $ hg update null --quiet
545 $ hg update null --quiet
530 $ hg heads -T '{desc}\n'
546 $ hg heads -T '{desc}\n'
531 A_4
547 A_4
532 B_1
548 B_1
533 #if v2
549 #if v2
534 $ show_cache
550 $ show_cache
535 ##### .hg/cache/branch2-served
551 ##### .hg/cache/branch2-served
536 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
552 3d808bbc94408ea19da905596d4079357a1f28be 8 f8006d64a10d35c011a5c5fa88be1e25c5929514
537 550bb31f072912453ccbb503de1d554616911e88 o default
553 550bb31f072912453ccbb503de1d554616911e88 o default
538 3d808bbc94408ea19da905596d4079357a1f28be o default
554 3d808bbc94408ea19da905596d4079357a1f28be o default
539 #else
555 #else
540 $ show_cache
556 $ show_cache
541 ##### .hg/cache/branch3-served
557 ##### .hg/cache/branch3-served
542 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8
558 filtered-hash=f8006d64a10d35c011a5c5fa88be1e25c5929514 tip-node=3d808bbc94408ea19da905596d4079357a1f28be tip-rev=8 topo-mode=pure
559 default
543 #endif
560 #endif
544
561
545 $ cd ..
562 $ cd ..
546 $ rm -rf tmp-repo
563 $ rm -rf tmp-repo
@@ -1,1380 +1,1384 b''
1 #testcases mmap nommap
1 #testcases mmap nommap
2 #testcases v2 v3
2 #testcases v2 v3
3
3
4 #if mmap
4 #if mmap
5 $ cat <<EOF >> $HGRCPATH
5 $ cat <<EOF >> $HGRCPATH
6 > [storage]
6 > [storage]
7 > revbranchcache.mmap=true
7 > revbranchcache.mmap=true
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 #if v3
11 #if v3
12 $ cat <<EOF >> $HGRCPATH
12 $ cat <<EOF >> $HGRCPATH
13 > [experimental]
13 > [experimental]
14 > branch-cache-v3=yes
14 > branch-cache-v3=yes
15 > EOF
15 > EOF
16 #else
16 #else
17 $ cat <<EOF >> $HGRCPATH
17 $ cat <<EOF >> $HGRCPATH
18 > [experimental]
18 > [experimental]
19 > branch-cache-v3=no
19 > branch-cache-v3=no
20 > EOF
20 > EOF
21 #endif
21 #endif
22
22
23 $ hg init a
23 $ hg init a
24 $ cd a
24 $ cd a
25
25
26 Verify checking branch of nullrev before the cache is created doesnt crash
26 Verify checking branch of nullrev before the cache is created doesnt crash
27 $ hg log -r 'branch(.)' -T '{branch}\n'
27 $ hg log -r 'branch(.)' -T '{branch}\n'
28
28
29 Basic test
29 Basic test
30 $ echo 'root' >root
30 $ echo 'root' >root
31 $ hg add root
31 $ hg add root
32 $ hg commit -d '0 0' -m "Adding root node"
32 $ hg commit -d '0 0' -m "Adding root node"
33
33
34 $ echo 'a' >a
34 $ echo 'a' >a
35 $ hg add a
35 $ hg add a
36 $ hg branch a
36 $ hg branch a
37 marked working directory as branch a
37 marked working directory as branch a
38 (branches are permanent and global, did you want a bookmark?)
38 (branches are permanent and global, did you want a bookmark?)
39 $ hg commit -d '1 0' -m "Adding a branch"
39 $ hg commit -d '1 0' -m "Adding a branch"
40
40
41 $ hg branch q
41 $ hg branch q
42 marked working directory as branch q
42 marked working directory as branch q
43 $ echo 'aa' >a
43 $ echo 'aa' >a
44 $ hg branch -C
44 $ hg branch -C
45 reset working directory to branch a
45 reset working directory to branch a
46 $ hg commit -d '2 0' -m "Adding to a branch"
46 $ hg commit -d '2 0' -m "Adding to a branch"
47
47
48 $ hg update -C 0
48 $ hg update -C 0
49 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
50 $ echo 'b' >b
50 $ echo 'b' >b
51 $ hg add b
51 $ hg add b
52 $ hg branch b
52 $ hg branch b
53 marked working directory as branch b
53 marked working directory as branch b
54 $ hg commit -d '2 0' -m "Adding b branch"
54 $ hg commit -d '2 0' -m "Adding b branch"
55
55
56 $ echo 'bh1' >bh1
56 $ echo 'bh1' >bh1
57 $ hg add bh1
57 $ hg add bh1
58 $ hg commit -d '3 0' -m "Adding b branch head 1"
58 $ hg commit -d '3 0' -m "Adding b branch head 1"
59
59
60 $ hg update -C 2
60 $ hg update -C 2
61 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
62 $ echo 'bh2' >bh2
62 $ echo 'bh2' >bh2
63 $ hg add bh2
63 $ hg add bh2
64 $ hg commit -d '4 0' -m "Adding b branch head 2"
64 $ hg commit -d '4 0' -m "Adding b branch head 2"
65
65
66 $ echo 'c' >c
66 $ echo 'c' >c
67 $ hg add c
67 $ hg add c
68 $ hg branch c
68 $ hg branch c
69 marked working directory as branch c
69 marked working directory as branch c
70 $ hg commit -d '5 0' -m "Adding c branch"
70 $ hg commit -d '5 0' -m "Adding c branch"
71
71
72 reserved names
72 reserved names
73
73
74 $ hg branch tip
74 $ hg branch tip
75 abort: the name 'tip' is reserved
75 abort: the name 'tip' is reserved
76 [10]
76 [10]
77 $ hg branch null
77 $ hg branch null
78 abort: the name 'null' is reserved
78 abort: the name 'null' is reserved
79 [10]
79 [10]
80 $ hg branch .
80 $ hg branch .
81 abort: the name '.' is reserved
81 abort: the name '.' is reserved
82 [10]
82 [10]
83
83
84 invalid characters
84 invalid characters
85
85
86 $ hg branch 'foo:bar'
86 $ hg branch 'foo:bar'
87 abort: ':' cannot be used in a name
87 abort: ':' cannot be used in a name
88 [10]
88 [10]
89
89
90 $ hg branch 'foo
90 $ hg branch 'foo
91 > bar'
91 > bar'
92 abort: '\n' cannot be used in a name
92 abort: '\n' cannot be used in a name
93 [10]
93 [10]
94
94
95 trailing or leading spaces should be stripped before testing duplicates
95 trailing or leading spaces should be stripped before testing duplicates
96
96
97 $ hg branch 'b '
97 $ hg branch 'b '
98 abort: a branch of the same name already exists
98 abort: a branch of the same name already exists
99 (use 'hg update' to switch to it)
99 (use 'hg update' to switch to it)
100 [10]
100 [10]
101
101
102 $ hg branch ' b'
102 $ hg branch ' b'
103 abort: a branch of the same name already exists
103 abort: a branch of the same name already exists
104 (use 'hg update' to switch to it)
104 (use 'hg update' to switch to it)
105 [10]
105 [10]
106
106
107 underscores in numeric branch names (issue6737)
107 underscores in numeric branch names (issue6737)
108
108
109 $ hg branch 2700_210
109 $ hg branch 2700_210
110 marked working directory as branch 2700_210
110 marked working directory as branch 2700_210
111
111
112 verify update will accept invalid legacy branch names
112 verify update will accept invalid legacy branch names
113
113
114 $ hg init test-invalid-branch-name
114 $ hg init test-invalid-branch-name
115 $ cd test-invalid-branch-name
115 $ cd test-invalid-branch-name
116 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
116 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 3 changesets with 3 changes to 2 files
120 added 3 changesets with 3 changes to 2 files
121 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
121 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
122 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
123
123
124 $ hg update '"colon:test"'
124 $ hg update '"colon:test"'
125 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 $ cd ..
126 $ cd ..
127
127
128 $ echo 'd' >d
128 $ echo 'd' >d
129 $ hg add d
129 $ hg add d
130 $ hg branch 'a branch name much longer than the default justification used by branches'
130 $ hg branch 'a branch name much longer than the default justification used by branches'
131 marked working directory as branch a branch name much longer than the default justification used by branches
131 marked working directory as branch a branch name much longer than the default justification used by branches
132 $ hg commit -d '6 0' -m "Adding d branch"
132 $ hg commit -d '6 0' -m "Adding d branch"
133
133
134 $ hg branches
134 $ hg branches
135 a branch name much longer than the default justification used by branches 7:10ff5895aa57
135 a branch name much longer than the default justification used by branches 7:10ff5895aa57
136 b 4:aee39cd168d0
136 b 4:aee39cd168d0
137 c 6:589736a22561 (inactive)
137 c 6:589736a22561 (inactive)
138 a 5:d8cbc61dbaa6 (inactive)
138 a 5:d8cbc61dbaa6 (inactive)
139 default 0:19709c5a4e75 (inactive)
139 default 0:19709c5a4e75 (inactive)
140
140
141 -------
141 -------
142
142
143 $ hg branches -a
143 $ hg branches -a
144 a branch name much longer than the default justification used by branches 7:10ff5895aa57
144 a branch name much longer than the default justification used by branches 7:10ff5895aa57
145 b 4:aee39cd168d0
145 b 4:aee39cd168d0
146
146
147 --- Branch a
147 --- Branch a
148
148
149 $ hg log -b a
149 $ hg log -b a
150 changeset: 5:d8cbc61dbaa6
150 changeset: 5:d8cbc61dbaa6
151 branch: a
151 branch: a
152 parent: 2:881fe2b92ad0
152 parent: 2:881fe2b92ad0
153 user: test
153 user: test
154 date: Thu Jan 01 00:00:04 1970 +0000
154 date: Thu Jan 01 00:00:04 1970 +0000
155 summary: Adding b branch head 2
155 summary: Adding b branch head 2
156
156
157 changeset: 2:881fe2b92ad0
157 changeset: 2:881fe2b92ad0
158 branch: a
158 branch: a
159 user: test
159 user: test
160 date: Thu Jan 01 00:00:02 1970 +0000
160 date: Thu Jan 01 00:00:02 1970 +0000
161 summary: Adding to a branch
161 summary: Adding to a branch
162
162
163 changeset: 1:dd6b440dd85a
163 changeset: 1:dd6b440dd85a
164 branch: a
164 branch: a
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:01 1970 +0000
166 date: Thu Jan 01 00:00:01 1970 +0000
167 summary: Adding a branch
167 summary: Adding a branch
168
168
169
169
170 ---- Branch b
170 ---- Branch b
171
171
172 $ hg log -b b
172 $ hg log -b b
173 changeset: 4:aee39cd168d0
173 changeset: 4:aee39cd168d0
174 branch: b
174 branch: b
175 user: test
175 user: test
176 date: Thu Jan 01 00:00:03 1970 +0000
176 date: Thu Jan 01 00:00:03 1970 +0000
177 summary: Adding b branch head 1
177 summary: Adding b branch head 1
178
178
179 changeset: 3:ac22033332d1
179 changeset: 3:ac22033332d1
180 branch: b
180 branch: b
181 parent: 0:19709c5a4e75
181 parent: 0:19709c5a4e75
182 user: test
182 user: test
183 date: Thu Jan 01 00:00:02 1970 +0000
183 date: Thu Jan 01 00:00:02 1970 +0000
184 summary: Adding b branch
184 summary: Adding b branch
185
185
186
186
187 ---- going to test branch listing by rev
187 ---- going to test branch listing by rev
188 $ hg branches -r0
188 $ hg branches -r0
189 default 0:19709c5a4e75 (inactive)
189 default 0:19709c5a4e75 (inactive)
190 $ hg branches -qr0
190 $ hg branches -qr0
191 default
191 default
192 --- now more than one rev
192 --- now more than one rev
193 $ hg branches -r2:5
193 $ hg branches -r2:5
194 b 4:aee39cd168d0
194 b 4:aee39cd168d0
195 a 5:d8cbc61dbaa6 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
196 $ hg branches -qr2:5
196 $ hg branches -qr2:5
197 b
197 b
198 a
198 a
199 ---- going to test branch closing
199 ---- going to test branch closing
200
200
201 $ hg branches
201 $ hg branches
202 a branch name much longer than the default justification used by branches 7:10ff5895aa57
202 a branch name much longer than the default justification used by branches 7:10ff5895aa57
203 b 4:aee39cd168d0
203 b 4:aee39cd168d0
204 c 6:589736a22561 (inactive)
204 c 6:589736a22561 (inactive)
205 a 5:d8cbc61dbaa6 (inactive)
205 a 5:d8cbc61dbaa6 (inactive)
206 default 0:19709c5a4e75 (inactive)
206 default 0:19709c5a4e75 (inactive)
207 $ hg up -C b
207 $ hg up -C b
208 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
208 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
209 $ echo 'xxx1' >> b
209 $ echo 'xxx1' >> b
210 $ hg commit -d '7 0' -m 'adding cset to branch b'
210 $ hg commit -d '7 0' -m 'adding cset to branch b'
211 $ hg up -C aee39cd168d0
211 $ hg up -C aee39cd168d0
212 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 $ echo 'xxx2' >> b
213 $ echo 'xxx2' >> b
214 $ hg commit -d '8 0' -m 'adding head to branch b'
214 $ hg commit -d '8 0' -m 'adding head to branch b'
215 created new head
215 created new head
216 $ echo 'xxx3' >> b
216 $ echo 'xxx3' >> b
217 $ hg commit -d '9 0' -m 'adding another cset to branch b'
217 $ hg commit -d '9 0' -m 'adding another cset to branch b'
218 $ hg branches
218 $ hg branches
219 b 10:bfbe841b666e
219 b 10:bfbe841b666e
220 a branch name much longer than the default justification used by branches 7:10ff5895aa57
220 a branch name much longer than the default justification used by branches 7:10ff5895aa57
221 c 6:589736a22561 (inactive)
221 c 6:589736a22561 (inactive)
222 a 5:d8cbc61dbaa6 (inactive)
222 a 5:d8cbc61dbaa6 (inactive)
223 default 0:19709c5a4e75 (inactive)
223 default 0:19709c5a4e75 (inactive)
224 $ hg heads --closed
224 $ hg heads --closed
225 changeset: 10:bfbe841b666e
225 changeset: 10:bfbe841b666e
226 branch: b
226 branch: b
227 tag: tip
227 tag: tip
228 user: test
228 user: test
229 date: Thu Jan 01 00:00:09 1970 +0000
229 date: Thu Jan 01 00:00:09 1970 +0000
230 summary: adding another cset to branch b
230 summary: adding another cset to branch b
231
231
232 changeset: 8:eebb944467c9
232 changeset: 8:eebb944467c9
233 branch: b
233 branch: b
234 parent: 4:aee39cd168d0
234 parent: 4:aee39cd168d0
235 user: test
235 user: test
236 date: Thu Jan 01 00:00:07 1970 +0000
236 date: Thu Jan 01 00:00:07 1970 +0000
237 summary: adding cset to branch b
237 summary: adding cset to branch b
238
238
239 changeset: 7:10ff5895aa57
239 changeset: 7:10ff5895aa57
240 branch: a branch name much longer than the default justification used by branches
240 branch: a branch name much longer than the default justification used by branches
241 user: test
241 user: test
242 date: Thu Jan 01 00:00:06 1970 +0000
242 date: Thu Jan 01 00:00:06 1970 +0000
243 summary: Adding d branch
243 summary: Adding d branch
244
244
245 changeset: 6:589736a22561
245 changeset: 6:589736a22561
246 branch: c
246 branch: c
247 user: test
247 user: test
248 date: Thu Jan 01 00:00:05 1970 +0000
248 date: Thu Jan 01 00:00:05 1970 +0000
249 summary: Adding c branch
249 summary: Adding c branch
250
250
251 changeset: 5:d8cbc61dbaa6
251 changeset: 5:d8cbc61dbaa6
252 branch: a
252 branch: a
253 parent: 2:881fe2b92ad0
253 parent: 2:881fe2b92ad0
254 user: test
254 user: test
255 date: Thu Jan 01 00:00:04 1970 +0000
255 date: Thu Jan 01 00:00:04 1970 +0000
256 summary: Adding b branch head 2
256 summary: Adding b branch head 2
257
257
258 changeset: 0:19709c5a4e75
258 changeset: 0:19709c5a4e75
259 user: test
259 user: test
260 date: Thu Jan 01 00:00:00 1970 +0000
260 date: Thu Jan 01 00:00:00 1970 +0000
261 summary: Adding root node
261 summary: Adding root node
262
262
263 $ hg heads
263 $ hg heads
264 changeset: 10:bfbe841b666e
264 changeset: 10:bfbe841b666e
265 branch: b
265 branch: b
266 tag: tip
266 tag: tip
267 user: test
267 user: test
268 date: Thu Jan 01 00:00:09 1970 +0000
268 date: Thu Jan 01 00:00:09 1970 +0000
269 summary: adding another cset to branch b
269 summary: adding another cset to branch b
270
270
271 changeset: 8:eebb944467c9
271 changeset: 8:eebb944467c9
272 branch: b
272 branch: b
273 parent: 4:aee39cd168d0
273 parent: 4:aee39cd168d0
274 user: test
274 user: test
275 date: Thu Jan 01 00:00:07 1970 +0000
275 date: Thu Jan 01 00:00:07 1970 +0000
276 summary: adding cset to branch b
276 summary: adding cset to branch b
277
277
278 changeset: 7:10ff5895aa57
278 changeset: 7:10ff5895aa57
279 branch: a branch name much longer than the default justification used by branches
279 branch: a branch name much longer than the default justification used by branches
280 user: test
280 user: test
281 date: Thu Jan 01 00:00:06 1970 +0000
281 date: Thu Jan 01 00:00:06 1970 +0000
282 summary: Adding d branch
282 summary: Adding d branch
283
283
284 changeset: 6:589736a22561
284 changeset: 6:589736a22561
285 branch: c
285 branch: c
286 user: test
286 user: test
287 date: Thu Jan 01 00:00:05 1970 +0000
287 date: Thu Jan 01 00:00:05 1970 +0000
288 summary: Adding c branch
288 summary: Adding c branch
289
289
290 changeset: 5:d8cbc61dbaa6
290 changeset: 5:d8cbc61dbaa6
291 branch: a
291 branch: a
292 parent: 2:881fe2b92ad0
292 parent: 2:881fe2b92ad0
293 user: test
293 user: test
294 date: Thu Jan 01 00:00:04 1970 +0000
294 date: Thu Jan 01 00:00:04 1970 +0000
295 summary: Adding b branch head 2
295 summary: Adding b branch head 2
296
296
297 changeset: 0:19709c5a4e75
297 changeset: 0:19709c5a4e75
298 user: test
298 user: test
299 date: Thu Jan 01 00:00:00 1970 +0000
299 date: Thu Jan 01 00:00:00 1970 +0000
300 summary: Adding root node
300 summary: Adding root node
301
301
302 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
302 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
303 $ hg branches -a
303 $ hg branches -a
304 b 8:eebb944467c9
304 b 8:eebb944467c9
305 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
306 $ hg up -C b
306 $ hg up -C b
307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
308 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
309 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
309 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
310 abort: current revision is already a branch closing head
310 abort: current revision is already a branch closing head
311 [10]
311 [10]
312
312
313 $ echo foo > b
313 $ echo foo > b
314 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
314 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
315
315
316 $ echo bar > b
316 $ echo bar > b
317 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' bh1
317 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' bh1
318 abort: current revision is already a branch closing head
318 abort: current revision is already a branch closing head
319 [10]
319 [10]
320 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' b
320 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' b
321
321
322 $ echo baz > b
322 $ echo baz > b
323 $ hg commit -d '9 0' --close-branch -m 'empty re-closing this branch' -X b
323 $ hg commit -d '9 0' --close-branch -m 'empty re-closing this branch' -X b
324 abort: current revision is already a branch closing head
324 abort: current revision is already a branch closing head
325 [10]
325 [10]
326 $ hg revert b
326 $ hg revert b
327
327
328 $ hg debugstrip --rev 13: --no-backup
328 $ hg debugstrip --rev 13: --no-backup
329 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 $ hg revert --all --no-backup
330 $ hg revert --all --no-backup
331
331
332 $ hg log -r tip --debug
332 $ hg log -r tip --debug
333 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
333 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
334 branch: b
334 branch: b
335 tag: tip
335 tag: tip
336 phase: draft
336 phase: draft
337 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
337 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
338 parent: -1:0000000000000000000000000000000000000000
338 parent: -1:0000000000000000000000000000000000000000
339 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
339 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
340 user: test
340 user: test
341 date: Thu Jan 01 00:00:09 1970 +0000
341 date: Thu Jan 01 00:00:09 1970 +0000
342 extra: branch=b
342 extra: branch=b
343 extra: close=1
343 extra: close=1
344 description:
344 description:
345 close this part branch too
345 close this part branch too
346
346
347
347
348 --- b branch should be inactive
348 --- b branch should be inactive
349
349
350 $ hg branches
350 $ hg branches
351 a branch name much longer than the default justification used by branches 7:10ff5895aa57
351 a branch name much longer than the default justification used by branches 7:10ff5895aa57
352 c 6:589736a22561 (inactive)
352 c 6:589736a22561 (inactive)
353 a 5:d8cbc61dbaa6 (inactive)
353 a 5:d8cbc61dbaa6 (inactive)
354 default 0:19709c5a4e75 (inactive)
354 default 0:19709c5a4e75 (inactive)
355 $ hg branches -c
355 $ hg branches -c
356 a branch name much longer than the default justification used by branches 7:10ff5895aa57
356 a branch name much longer than the default justification used by branches 7:10ff5895aa57
357 b 12:e3d49c0575d8 (closed)
357 b 12:e3d49c0575d8 (closed)
358 c 6:589736a22561 (inactive)
358 c 6:589736a22561 (inactive)
359 a 5:d8cbc61dbaa6 (inactive)
359 a 5:d8cbc61dbaa6 (inactive)
360 default 0:19709c5a4e75 (inactive)
360 default 0:19709c5a4e75 (inactive)
361 $ hg branches -a
361 $ hg branches -a
362 a branch name much longer than the default justification used by branches 7:10ff5895aa57
362 a branch name much longer than the default justification used by branches 7:10ff5895aa57
363 $ hg branches -q
363 $ hg branches -q
364 a branch name much longer than the default justification used by branches
364 a branch name much longer than the default justification used by branches
365 c
365 c
366 a
366 a
367 default
367 default
368 $ hg heads b
368 $ hg heads b
369 no open branch heads found on branches b
369 no open branch heads found on branches b
370 [1]
370 [1]
371 $ hg heads --closed b
371 $ hg heads --closed b
372 changeset: 12:e3d49c0575d8
372 changeset: 12:e3d49c0575d8
373 branch: b
373 branch: b
374 tag: tip
374 tag: tip
375 parent: 8:eebb944467c9
375 parent: 8:eebb944467c9
376 user: test
376 user: test
377 date: Thu Jan 01 00:00:09 1970 +0000
377 date: Thu Jan 01 00:00:09 1970 +0000
378 summary: close this part branch too
378 summary: close this part branch too
379
379
380 changeset: 11:d3f163457ebf
380 changeset: 11:d3f163457ebf
381 branch: b
381 branch: b
382 user: test
382 user: test
383 date: Thu Jan 01 00:00:09 1970 +0000
383 date: Thu Jan 01 00:00:09 1970 +0000
384 summary: prune bad branch
384 summary: prune bad branch
385
385
386 $ echo 'xxx4' >> b
386 $ echo 'xxx4' >> b
387 $ hg commit -d '9 0' -m 'reopen branch with a change'
387 $ hg commit -d '9 0' -m 'reopen branch with a change'
388 reopening closed branch head 12
388 reopening closed branch head 12
389
389
390 --- branch b is back in action
390 --- branch b is back in action
391
391
392 $ hg branches -a
392 $ hg branches -a
393 b 13:e23b5505d1ad
393 b 13:e23b5505d1ad
394 a branch name much longer than the default justification used by branches 7:10ff5895aa57
394 a branch name much longer than the default justification used by branches 7:10ff5895aa57
395
395
396 ---- test heads listings
396 ---- test heads listings
397
397
398 $ hg heads
398 $ hg heads
399 changeset: 13:e23b5505d1ad
399 changeset: 13:e23b5505d1ad
400 branch: b
400 branch: b
401 tag: tip
401 tag: tip
402 user: test
402 user: test
403 date: Thu Jan 01 00:00:09 1970 +0000
403 date: Thu Jan 01 00:00:09 1970 +0000
404 summary: reopen branch with a change
404 summary: reopen branch with a change
405
405
406 changeset: 7:10ff5895aa57
406 changeset: 7:10ff5895aa57
407 branch: a branch name much longer than the default justification used by branches
407 branch: a branch name much longer than the default justification used by branches
408 user: test
408 user: test
409 date: Thu Jan 01 00:00:06 1970 +0000
409 date: Thu Jan 01 00:00:06 1970 +0000
410 summary: Adding d branch
410 summary: Adding d branch
411
411
412 changeset: 6:589736a22561
412 changeset: 6:589736a22561
413 branch: c
413 branch: c
414 user: test
414 user: test
415 date: Thu Jan 01 00:00:05 1970 +0000
415 date: Thu Jan 01 00:00:05 1970 +0000
416 summary: Adding c branch
416 summary: Adding c branch
417
417
418 changeset: 5:d8cbc61dbaa6
418 changeset: 5:d8cbc61dbaa6
419 branch: a
419 branch: a
420 parent: 2:881fe2b92ad0
420 parent: 2:881fe2b92ad0
421 user: test
421 user: test
422 date: Thu Jan 01 00:00:04 1970 +0000
422 date: Thu Jan 01 00:00:04 1970 +0000
423 summary: Adding b branch head 2
423 summary: Adding b branch head 2
424
424
425 changeset: 0:19709c5a4e75
425 changeset: 0:19709c5a4e75
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:00 1970 +0000
427 date: Thu Jan 01 00:00:00 1970 +0000
428 summary: Adding root node
428 summary: Adding root node
429
429
430
430
431 branch default
431 branch default
432
432
433 $ hg heads default
433 $ hg heads default
434 changeset: 0:19709c5a4e75
434 changeset: 0:19709c5a4e75
435 user: test
435 user: test
436 date: Thu Jan 01 00:00:00 1970 +0000
436 date: Thu Jan 01 00:00:00 1970 +0000
437 summary: Adding root node
437 summary: Adding root node
438
438
439
439
440 branch a
440 branch a
441
441
442 $ hg heads a
442 $ hg heads a
443 changeset: 5:d8cbc61dbaa6
443 changeset: 5:d8cbc61dbaa6
444 branch: a
444 branch: a
445 parent: 2:881fe2b92ad0
445 parent: 2:881fe2b92ad0
446 user: test
446 user: test
447 date: Thu Jan 01 00:00:04 1970 +0000
447 date: Thu Jan 01 00:00:04 1970 +0000
448 summary: Adding b branch head 2
448 summary: Adding b branch head 2
449
449
450 $ hg heads --active a
450 $ hg heads --active a
451 no open branch heads found on branches a
451 no open branch heads found on branches a
452 [1]
452 [1]
453
453
454 branch b
454 branch b
455
455
456 $ hg heads b
456 $ hg heads b
457 changeset: 13:e23b5505d1ad
457 changeset: 13:e23b5505d1ad
458 branch: b
458 branch: b
459 tag: tip
459 tag: tip
460 user: test
460 user: test
461 date: Thu Jan 01 00:00:09 1970 +0000
461 date: Thu Jan 01 00:00:09 1970 +0000
462 summary: reopen branch with a change
462 summary: reopen branch with a change
463
463
464 $ hg heads --closed b
464 $ hg heads --closed b
465 changeset: 13:e23b5505d1ad
465 changeset: 13:e23b5505d1ad
466 branch: b
466 branch: b
467 tag: tip
467 tag: tip
468 user: test
468 user: test
469 date: Thu Jan 01 00:00:09 1970 +0000
469 date: Thu Jan 01 00:00:09 1970 +0000
470 summary: reopen branch with a change
470 summary: reopen branch with a change
471
471
472 changeset: 11:d3f163457ebf
472 changeset: 11:d3f163457ebf
473 branch: b
473 branch: b
474 user: test
474 user: test
475 date: Thu Jan 01 00:00:09 1970 +0000
475 date: Thu Jan 01 00:00:09 1970 +0000
476 summary: prune bad branch
476 summary: prune bad branch
477
477
478
478
479 reclose branch
479 reclose branch
480
480
481 $ hg up -C c
481 $ hg up -C c
482 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
482 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
483 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
483 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
484 $ hg branches
484 $ hg branches
485 b 13:e23b5505d1ad
485 b 13:e23b5505d1ad
486 a branch name much longer than the default justification used by branches 7:10ff5895aa57
486 a branch name much longer than the default justification used by branches 7:10ff5895aa57
487 a 5:d8cbc61dbaa6 (inactive)
487 a 5:d8cbc61dbaa6 (inactive)
488 default 0:19709c5a4e75 (inactive)
488 default 0:19709c5a4e75 (inactive)
489 $ hg branches --closed
489 $ hg branches --closed
490 b 13:e23b5505d1ad
490 b 13:e23b5505d1ad
491 a branch name much longer than the default justification used by branches 7:10ff5895aa57
491 a branch name much longer than the default justification used by branches 7:10ff5895aa57
492 c 14:f894c25619d3 (closed)
492 c 14:f894c25619d3 (closed)
493 a 5:d8cbc61dbaa6 (inactive)
493 a 5:d8cbc61dbaa6 (inactive)
494 default 0:19709c5a4e75 (inactive)
494 default 0:19709c5a4e75 (inactive)
495
495
496 multihead branch
496 multihead branch
497
497
498 $ hg up -C default
498 $ hg up -C default
499 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
499 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
500 $ hg branch m
500 $ hg branch m
501 marked working directory as branch m
501 marked working directory as branch m
502 $ touch m
502 $ touch m
503 $ hg add m
503 $ hg add m
504 $ hg commit -d '10 0' -m 'multihead base'
504 $ hg commit -d '10 0' -m 'multihead base'
505 $ echo "m1" >m
505 $ echo "m1" >m
506 $ hg commit -d '10 0' -m 'head 1'
506 $ hg commit -d '10 0' -m 'head 1'
507 $ hg up -C '.^'
507 $ hg up -C '.^'
508 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
508 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 $ echo "m2" >m
509 $ echo "m2" >m
510 $ hg commit -d '10 0' -m 'head 2'
510 $ hg commit -d '10 0' -m 'head 2'
511 created new head
511 created new head
512 $ hg log -b m
512 $ hg log -b m
513 changeset: 17:df343b0df04f
513 changeset: 17:df343b0df04f
514 branch: m
514 branch: m
515 tag: tip
515 tag: tip
516 parent: 15:f3447637f53e
516 parent: 15:f3447637f53e
517 user: test
517 user: test
518 date: Thu Jan 01 00:00:10 1970 +0000
518 date: Thu Jan 01 00:00:10 1970 +0000
519 summary: head 2
519 summary: head 2
520
520
521 changeset: 16:a58ca5d3bdf3
521 changeset: 16:a58ca5d3bdf3
522 branch: m
522 branch: m
523 user: test
523 user: test
524 date: Thu Jan 01 00:00:10 1970 +0000
524 date: Thu Jan 01 00:00:10 1970 +0000
525 summary: head 1
525 summary: head 1
526
526
527 changeset: 15:f3447637f53e
527 changeset: 15:f3447637f53e
528 branch: m
528 branch: m
529 parent: 0:19709c5a4e75
529 parent: 0:19709c5a4e75
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:10 1970 +0000
531 date: Thu Jan 01 00:00:10 1970 +0000
532 summary: multihead base
532 summary: multihead base
533
533
534 $ hg heads --topo m
534 $ hg heads --topo m
535 changeset: 17:df343b0df04f
535 changeset: 17:df343b0df04f
536 branch: m
536 branch: m
537 tag: tip
537 tag: tip
538 parent: 15:f3447637f53e
538 parent: 15:f3447637f53e
539 user: test
539 user: test
540 date: Thu Jan 01 00:00:10 1970 +0000
540 date: Thu Jan 01 00:00:10 1970 +0000
541 summary: head 2
541 summary: head 2
542
542
543 changeset: 16:a58ca5d3bdf3
543 changeset: 16:a58ca5d3bdf3
544 branch: m
544 branch: m
545 user: test
545 user: test
546 date: Thu Jan 01 00:00:10 1970 +0000
546 date: Thu Jan 01 00:00:10 1970 +0000
547 summary: head 1
547 summary: head 1
548
548
549 $ hg branches
549 $ hg branches
550 m 17:df343b0df04f
550 m 17:df343b0df04f
551 b 13:e23b5505d1ad
551 b 13:e23b5505d1ad
552 a branch name much longer than the default justification used by branches 7:10ff5895aa57
552 a branch name much longer than the default justification used by branches 7:10ff5895aa57
553 a 5:d8cbc61dbaa6 (inactive)
553 a 5:d8cbc61dbaa6 (inactive)
554 default 0:19709c5a4e75 (inactive)
554 default 0:19709c5a4e75 (inactive)
555
555
556 partially merge multihead branch
556 partially merge multihead branch
557
557
558 $ hg up -C default
558 $ hg up -C default
559 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
559 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
560 $ hg branch md
560 $ hg branch md
561 marked working directory as branch md
561 marked working directory as branch md
562 $ hg merge m
562 $ hg merge m
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 (branch merge, don't forget to commit)
564 (branch merge, don't forget to commit)
565 $ hg commit -d '11 0' -m 'merge head 2'
565 $ hg commit -d '11 0' -m 'merge head 2'
566 $ hg heads --topo m
566 $ hg heads --topo m
567 changeset: 16:a58ca5d3bdf3
567 changeset: 16:a58ca5d3bdf3
568 branch: m
568 branch: m
569 user: test
569 user: test
570 date: Thu Jan 01 00:00:10 1970 +0000
570 date: Thu Jan 01 00:00:10 1970 +0000
571 summary: head 1
571 summary: head 1
572
572
573 $ hg branches
573 $ hg branches
574 md 18:c914c99f1fbb
574 md 18:c914c99f1fbb
575 m 17:df343b0df04f
575 m 17:df343b0df04f
576 b 13:e23b5505d1ad
576 b 13:e23b5505d1ad
577 a branch name much longer than the default justification used by branches 7:10ff5895aa57
577 a branch name much longer than the default justification used by branches 7:10ff5895aa57
578 a 5:d8cbc61dbaa6 (inactive)
578 a 5:d8cbc61dbaa6 (inactive)
579 default 0:19709c5a4e75 (inactive)
579 default 0:19709c5a4e75 (inactive)
580
580
581 partially close multihead branch
581 partially close multihead branch
582
582
583 $ hg up -C a58ca5d3bdf3
583 $ hg up -C a58ca5d3bdf3
584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
585 $ hg commit -d '12 0' -m 'close head 1' --close-branch
585 $ hg commit -d '12 0' -m 'close head 1' --close-branch
586 $ hg heads --topo m
586 $ hg heads --topo m
587 changeset: 19:cd21a80baa3d
587 changeset: 19:cd21a80baa3d
588 branch: m
588 branch: m
589 tag: tip
589 tag: tip
590 parent: 16:a58ca5d3bdf3
590 parent: 16:a58ca5d3bdf3
591 user: test
591 user: test
592 date: Thu Jan 01 00:00:12 1970 +0000
592 date: Thu Jan 01 00:00:12 1970 +0000
593 summary: close head 1
593 summary: close head 1
594
594
595 $ hg branches
595 $ hg branches
596 md 18:c914c99f1fbb
596 md 18:c914c99f1fbb
597 b 13:e23b5505d1ad
597 b 13:e23b5505d1ad
598 a branch name much longer than the default justification used by branches 7:10ff5895aa57
598 a branch name much longer than the default justification used by branches 7:10ff5895aa57
599 m 17:df343b0df04f (inactive)
599 m 17:df343b0df04f (inactive)
600 a 5:d8cbc61dbaa6 (inactive)
600 a 5:d8cbc61dbaa6 (inactive)
601 default 0:19709c5a4e75 (inactive)
601 default 0:19709c5a4e75 (inactive)
602
602
603 default branch colors:
603 default branch colors:
604
604
605 $ cat <<EOF >> $HGRCPATH
605 $ cat <<EOF >> $HGRCPATH
606 > [extensions]
606 > [extensions]
607 > color =
607 > color =
608 > [color]
608 > [color]
609 > mode = ansi
609 > mode = ansi
610 > EOF
610 > EOF
611
611
612 $ hg up -C b
612 $ hg up -C b
613 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
613 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
614 $ hg branches --color=always
614 $ hg branches --color=always
615 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
615 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
616 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
616 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
617 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
617 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
618 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
618 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
619 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
619 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
620 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
620 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
621
621
622 default closed branch color:
622 default closed branch color:
623
623
624 $ hg branches --color=always --closed
624 $ hg branches --color=always --closed
625 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
625 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
626 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
626 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
627 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
627 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
628 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
628 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
629 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
629 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
630 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
630 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
631 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
631 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
632
632
633 $ cat <<EOF >> $HGRCPATH
633 $ cat <<EOF >> $HGRCPATH
634 > [extensions]
634 > [extensions]
635 > color =
635 > color =
636 > [color]
636 > [color]
637 > branches.active = green
637 > branches.active = green
638 > branches.closed = blue
638 > branches.closed = blue
639 > branches.current = red
639 > branches.current = red
640 > branches.inactive = magenta
640 > branches.inactive = magenta
641 > log.changeset = cyan
641 > log.changeset = cyan
642 > EOF
642 > EOF
643
643
644 custom branch colors:
644 custom branch colors:
645
645
646 $ hg branches --color=always
646 $ hg branches --color=always
647 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
647 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
648 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
648 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
649 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
649 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
650 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
650 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
651 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
651 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
652 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
652 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
653
653
654 custom closed branch color:
654 custom closed branch color:
655
655
656 $ hg branches --color=always --closed
656 $ hg branches --color=always --closed
657 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
657 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
658 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
658 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
659 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
659 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
660 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
660 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
661 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
661 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
662 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
662 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
663 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
663 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
664
664
665 template output:
665 template output:
666
666
667 $ hg branches -Tjson --closed
667 $ hg branches -Tjson --closed
668 [
668 [
669 {
669 {
670 "active": true,
670 "active": true,
671 "branch": "md",
671 "branch": "md",
672 "closed": false,
672 "closed": false,
673 "current": false,
673 "current": false,
674 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
674 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
675 "rev": 18
675 "rev": 18
676 },
676 },
677 {
677 {
678 "active": true,
678 "active": true,
679 "branch": "b",
679 "branch": "b",
680 "closed": false,
680 "closed": false,
681 "current": true,
681 "current": true,
682 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
682 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
683 "rev": 13
683 "rev": 13
684 },
684 },
685 {
685 {
686 "active": true,
686 "active": true,
687 "branch": "a branch name much longer than the default justification used by branches",
687 "branch": "a branch name much longer than the default justification used by branches",
688 "closed": false,
688 "closed": false,
689 "current": false,
689 "current": false,
690 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
690 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
691 "rev": 7
691 "rev": 7
692 },
692 },
693 {
693 {
694 "active": false,
694 "active": false,
695 "branch": "m",
695 "branch": "m",
696 "closed": false,
696 "closed": false,
697 "current": false,
697 "current": false,
698 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
698 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
699 "rev": 17
699 "rev": 17
700 },
700 },
701 {
701 {
702 "active": false,
702 "active": false,
703 "branch": "c",
703 "branch": "c",
704 "closed": true,
704 "closed": true,
705 "current": false,
705 "current": false,
706 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
706 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
707 "rev": 14
707 "rev": 14
708 },
708 },
709 {
709 {
710 "active": false,
710 "active": false,
711 "branch": "a",
711 "branch": "a",
712 "closed": false,
712 "closed": false,
713 "current": false,
713 "current": false,
714 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
714 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
715 "rev": 5
715 "rev": 5
716 },
716 },
717 {
717 {
718 "active": false,
718 "active": false,
719 "branch": "default",
719 "branch": "default",
720 "closed": false,
720 "closed": false,
721 "current": false,
721 "current": false,
722 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
722 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
723 "rev": 0
723 "rev": 0
724 }
724 }
725 ]
725 ]
726
726
727 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
727 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
728 c
728 c
729
729
730 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
730 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
731 md: merge head 2
731 md: merge head 2
732 b: reopen branch with a change
732 b: reopen branch with a change
733 a: Adding d branch
733 a: Adding d branch
734 m: head 2
734 m: head 2
735 a: Adding b branch head 2
735 a: Adding b branch head 2
736 default: Adding root node
736 default: Adding root node
737
737
738 $ cat <<'EOF' > "$TESTTMP/map-myjson"
738 $ cat <<'EOF' > "$TESTTMP/map-myjson"
739 > docheader = '\{\n'
739 > docheader = '\{\n'
740 > docfooter = '\n}\n'
740 > docfooter = '\n}\n'
741 > separator = ',\n'
741 > separator = ',\n'
742 > branches = ' {dict(branch, node|short)|json}'
742 > branches = ' {dict(branch, node|short)|json}'
743 > EOF
743 > EOF
744 $ hg branches -T "$TESTTMP/map-myjson"
744 $ hg branches -T "$TESTTMP/map-myjson"
745 {
745 {
746 {"branch": "md", "node": "c914c99f1fbb"},
746 {"branch": "md", "node": "c914c99f1fbb"},
747 {"branch": "b", "node": "e23b5505d1ad"},
747 {"branch": "b", "node": "e23b5505d1ad"},
748 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
748 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
749 {"branch": "m", "node": "df343b0df04f"},
749 {"branch": "m", "node": "df343b0df04f"},
750 {"branch": "a", "node": "d8cbc61dbaa6"},
750 {"branch": "a", "node": "d8cbc61dbaa6"},
751 {"branch": "default", "node": "19709c5a4e75"}
751 {"branch": "default", "node": "19709c5a4e75"}
752 }
752 }
753
753
754 $ cat <<'EOF' >> .hg/hgrc
754 $ cat <<'EOF' >> .hg/hgrc
755 > [templates]
755 > [templates]
756 > myjson = ' {dict(branch, node|short)|json}'
756 > myjson = ' {dict(branch, node|short)|json}'
757 > myjson:docheader = '\{\n'
757 > myjson:docheader = '\{\n'
758 > myjson:docfooter = '\n}\n'
758 > myjson:docfooter = '\n}\n'
759 > myjson:separator = ',\n'
759 > myjson:separator = ',\n'
760 > EOF
760 > EOF
761 $ hg branches -T myjson
761 $ hg branches -T myjson
762 {
762 {
763 {"branch": "md", "node": "c914c99f1fbb"},
763 {"branch": "md", "node": "c914c99f1fbb"},
764 {"branch": "b", "node": "e23b5505d1ad"},
764 {"branch": "b", "node": "e23b5505d1ad"},
765 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
765 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
766 {"branch": "m", "node": "df343b0df04f"},
766 {"branch": "m", "node": "df343b0df04f"},
767 {"branch": "a", "node": "d8cbc61dbaa6"},
767 {"branch": "a", "node": "d8cbc61dbaa6"},
768 {"branch": "default", "node": "19709c5a4e75"}
768 {"branch": "default", "node": "19709c5a4e75"}
769 }
769 }
770
770
771 $ cat <<'EOF' >> .hg/hgrc
771 $ cat <<'EOF' >> .hg/hgrc
772 > [templates]
772 > [templates]
773 > :docheader = 'should not be selected as a docheader for literal templates\n'
773 > :docheader = 'should not be selected as a docheader for literal templates\n'
774 > EOF
774 > EOF
775 $ hg branches -T '{branch}\n'
775 $ hg branches -T '{branch}\n'
776 md
776 md
777 b
777 b
778 a branch name much longer than the default justification used by branches
778 a branch name much longer than the default justification used by branches
779 m
779 m
780 a
780 a
781 default
781 default
782
782
783 Tests of revision branch name caching
783 Tests of revision branch name caching
784
784
785 We rev branch cache is updated automatically. In these tests we use a trick to
785 We rev branch cache is updated automatically. In these tests we use a trick to
786 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
786 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
787 rebuild that also will populate the rev branch cache.
787 rebuild that also will populate the rev branch cache.
788
788
789 revision branch cache is created when building the branch head cache
789 revision branch cache is created when building the branch head cache
790 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
790 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
791 5
791 5
792 $ f --hexdump --size .hg/cache/rbc-*
792 $ f --hexdump --size .hg/cache/rbc-*
793 .hg/cache/rbc-names-v1: size=92
793 .hg/cache/rbc-names-v1: size=92
794 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
794 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
795 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
795 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
796 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
796 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
797 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
797 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
798 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
798 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
799 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
799 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
800 .hg/cache/rbc-revs-v1: size=160
800 .hg/cache/rbc-revs-v1: size=160
801 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
801 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
802 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
802 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
803 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
803 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
804 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
804 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
805 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
805 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
806 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
806 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
807 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
807 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
808 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
808 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
809 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
809 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
810 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
810 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
811
811
812 no errors when revbranchcache is not writable
812 no errors when revbranchcache is not writable
813
813
814 $ echo >> .hg/cache/rbc-revs-v1
814 $ echo >> .hg/cache/rbc-revs-v1
815 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
815 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
816 $ mkdir .hg/cache/rbc-revs-v1
816 $ mkdir .hg/cache/rbc-revs-v1
817 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
817 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
818 5
818 5
819 $ rmdir .hg/cache/rbc-revs-v1
819 $ rmdir .hg/cache/rbc-revs-v1
820 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
820 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
821
821
822 no errors when wlock cannot be acquired
822 no errors when wlock cannot be acquired
823
823
824 #if unix-permissions
824 #if unix-permissions
825 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
825 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
826 $ rm -f .hg/cache/branch*
826 $ rm -f .hg/cache/branch*
827 $ chmod 555 .hg
827 $ chmod 555 .hg
828 $ hg head a -T '{rev}\n'
828 $ hg head a -T '{rev}\n'
829 5
829 5
830 $ chmod 755 .hg
830 $ chmod 755 .hg
831 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
831 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
832 #endif
832 #endif
833
833
834 recovery from invalid cache revs file with trailing data
834 recovery from invalid cache revs file with trailing data
835 $ echo >> .hg/cache/rbc-revs-v1
835 $ echo >> .hg/cache/rbc-revs-v1
836 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
836 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
837 5
837 5
838 truncating cache/rbc-revs-v1 to 160
838 truncating cache/rbc-revs-v1 to 160
839 $ f --size .hg/cache/rbc-revs*
839 $ f --size .hg/cache/rbc-revs*
840 .hg/cache/rbc-revs-v1: size=160
840 .hg/cache/rbc-revs-v1: size=160
841
841
842 recovery from invalid cache file with partial last record
842 recovery from invalid cache file with partial last record
843 $ mv .hg/cache/rbc-revs-v1 .
843 $ mv .hg/cache/rbc-revs-v1 .
844 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
844 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
845 $ f --size .hg/cache/rbc-revs*
845 $ f --size .hg/cache/rbc-revs*
846 .hg/cache/rbc-revs-v1: size=119
846 .hg/cache/rbc-revs-v1: size=119
847 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
847 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
848 5
848 5
849 truncating cache/rbc-revs-v1 to 112
849 truncating cache/rbc-revs-v1 to 112
850 $ f --size .hg/cache/rbc-revs*
850 $ f --size .hg/cache/rbc-revs*
851 .hg/cache/rbc-revs-v1: size=160
851 .hg/cache/rbc-revs-v1: size=160
852
852
853 recovery from invalid cache file with missing record - no truncation
853 recovery from invalid cache file with missing record - no truncation
854 $ mv .hg/cache/rbc-revs-v1 .
854 $ mv .hg/cache/rbc-revs-v1 .
855 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
855 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
856 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
856 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
857 5
857 5
858 $ f --size .hg/cache/rbc-revs*
858 $ f --size .hg/cache/rbc-revs*
859 .hg/cache/rbc-revs-v1: size=160
859 .hg/cache/rbc-revs-v1: size=160
860
860
861 recovery from invalid cache file with some bad records
861 recovery from invalid cache file with some bad records
862 $ mv .hg/cache/rbc-revs-v1 .
862 $ mv .hg/cache/rbc-revs-v1 .
863 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
863 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
864 $ f --size .hg/cache/rbc-revs*
864 $ f --size .hg/cache/rbc-revs*
865 .hg/cache/rbc-revs-v1: size=8
865 .hg/cache/rbc-revs-v1: size=8
866 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
866 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
867 $ f --size .hg/cache/rbc-revs*
867 $ f --size .hg/cache/rbc-revs*
868 .hg/cache/rbc-revs-v1: size=120
868 .hg/cache/rbc-revs-v1: size=120
869 $ hg log -r 'branch(.)' -T '{rev} ' --debug
869 $ hg log -r 'branch(.)' -T '{rev} ' --debug
870 history modification detected - truncating revision branch cache to revision * (glob)
870 history modification detected - truncating revision branch cache to revision * (glob)
871 history modification detected - truncating revision branch cache to revision 1
871 history modification detected - truncating revision branch cache to revision 1
872 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
872 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
873 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
873 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
874 5
874 5
875 truncating cache/rbc-revs-v1 to 104
875 truncating cache/rbc-revs-v1 to 104
876 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
876 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
877 .hg/cache/rbc-revs-v1: size=160
877 .hg/cache/rbc-revs-v1: size=160
878 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
878 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
879
879
880 cache is updated when committing
880 cache is updated when committing
881 $ hg branch i-will-regret-this
881 $ hg branch i-will-regret-this
882 marked working directory as branch i-will-regret-this
882 marked working directory as branch i-will-regret-this
883 $ hg ci -m regrets
883 $ hg ci -m regrets
884 $ f --size .hg/cache/rbc-*
884 $ f --size .hg/cache/rbc-*
885 .hg/cache/rbc-names-v1: size=111
885 .hg/cache/rbc-names-v1: size=111
886 .hg/cache/rbc-revs-v1: size=168
886 .hg/cache/rbc-revs-v1: size=168
887
887
888 update after rollback - the cache will be correct but rbc-names will will still
888 update after rollback - the cache will be correct but rbc-names will will still
889 contain the branch name even though it no longer is used
889 contain the branch name even though it no longer is used
890 $ hg up -qr '.^'
890 $ hg up -qr '.^'
891 $ hg rollback -qf
891 $ hg rollback -qf
892 $ f --size .hg/cache/rbc-names-*
892 $ f --size .hg/cache/rbc-names-*
893 .hg/cache/rbc-names-v1: size=111
893 .hg/cache/rbc-names-v1: size=111
894 $ grep "i-will-regret-this" .hg/cache/rbc-names-* > /dev/null
894 $ grep "i-will-regret-this" .hg/cache/rbc-names-* > /dev/null
895 $ f --size .hg/cache/rbc-revs-*
895 $ f --size .hg/cache/rbc-revs-*
896 .hg/cache/rbc-revs-v1: size=160
896 .hg/cache/rbc-revs-v1: size=160
897
897
898 cache is updated/truncated when stripping - it is thus very hard to get in a
898 cache is updated/truncated when stripping - it is thus very hard to get in a
899 situation where the cache is out of sync and the hash check detects it
899 situation where the cache is out of sync and the hash check detects it
900 $ hg --config extensions.strip= strip -r tip --nob
900 $ hg --config extensions.strip= strip -r tip --nob
901 $ f --size .hg/cache/rbc-revs*
901 $ f --size .hg/cache/rbc-revs*
902 .hg/cache/rbc-revs-v1: size=152
902 .hg/cache/rbc-revs-v1: size=152
903
903
904 cache is rebuilt when corruption is detected
904 cache is rebuilt when corruption is detected
905 $ echo > .hg/cache/rbc-names-v1
905 $ echo > .hg/cache/rbc-names-v1
906 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
906 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
907 referenced branch names not found - rebuilding revision branch cache from scratch
907 referenced branch names not found - rebuilding revision branch cache from scratch
908 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
908 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
909 $ f --size .hg/cache/rbc-names-*
909 $ f --size .hg/cache/rbc-names-*
910 .hg/cache/rbc-names-v1: size=84
910 .hg/cache/rbc-names-v1: size=84
911 $ grep "i-will-regret-this" .hg/cache/rbc-names-* > /dev/null
911 $ grep "i-will-regret-this" .hg/cache/rbc-names-* > /dev/null
912 [1]
912 [1]
913 $ f --size .hg/cache/rbc-revs-*
913 $ f --size .hg/cache/rbc-revs-*
914 .hg/cache/rbc-revs-v1: size=152
914 .hg/cache/rbc-revs-v1: size=152
915
915
916 Test that cache files are created and grows correctly:
916 Test that cache files are created and grows correctly:
917
917
918 $ rm .hg/cache/rbc*
918 $ rm .hg/cache/rbc*
919 $ hg log -r "5 & branch(5)" -T "{rev}\n"
919 $ hg log -r "5 & branch(5)" -T "{rev}\n"
920 5
920 5
921
921
922 (here v3 is querying branch info for heads so it warm much more of the cache)
922 (here v3 is querying branch info for heads so it warm much more of the cache)
923
923
924 #if v2
924 #if v2
925 $ f --size .hg/cache/rbc-*
925 $ f --size .hg/cache/rbc-*
926 .hg/cache/rbc-names-v1: size=1
926 .hg/cache/rbc-names-v1: size=1
927 .hg/cache/rbc-revs-v1: size=48
927 .hg/cache/rbc-revs-v1: size=48
928 #else
928 #else
929 $ f --size .hg/cache/rbc-*
929 $ f --size .hg/cache/rbc-*
930 .hg/cache/rbc-names-v1: size=84
930 .hg/cache/rbc-names-v1: size=84
931 .hg/cache/rbc-revs-v1: size=152
931 .hg/cache/rbc-revs-v1: size=152
932 #endif
932 #endif
933
933
934 $ cd ..
934 $ cd ..
935
935
936 Test for multiple incorrect branch cache entries:
936 Test for multiple incorrect branch cache entries:
937
937
938 $ hg init b
938 $ hg init b
939 $ cd b
939 $ cd b
940 $ touch f
940 $ touch f
941 $ hg ci -Aqmf
941 $ hg ci -Aqmf
942 $ echo >> f
942 $ echo >> f
943 $ hg ci -Amf
943 $ hg ci -Amf
944 $ hg branch -q branch
944 $ hg branch -q branch
945 $ hg ci -Amf
945 $ hg ci -Amf
946
946
947 #if v2
947 #if v2
948
948
949 $ f --size --sha256 .hg/cache/rbc-*
949 $ f --size --sha256 .hg/cache/rbc-*
950 .hg/cache/rbc-names-v1: size=14, sha256=d376f7eea9a7e28fac6470e78dae753c81a5543c9ad436e96999590e004a281c
950 .hg/cache/rbc-names-v1: size=14, sha256=d376f7eea9a7e28fac6470e78dae753c81a5543c9ad436e96999590e004a281c
951 .hg/cache/rbc-revs-v1: size=24, sha256=ec89032fd4e66e7282cb6e403848c681a855a9c36c6b44d19179218553b78779
951 .hg/cache/rbc-revs-v1: size=24, sha256=ec89032fd4e66e7282cb6e403848c681a855a9c36c6b44d19179218553b78779
952
952
953 $ : > .hg/cache/rbc-revs-v1
953 $ : > .hg/cache/rbc-revs-v1
954
954
955 No superfluous rebuilding of cache:
955 No superfluous rebuilding of cache:
956 $ hg log -r "branch(null)&branch(branch)" --debug
956 $ hg log -r "branch(null)&branch(branch)" --debug
957 $ f --size --sha256 .hg/cache/rbc-*
957 $ f --size --sha256 .hg/cache/rbc-*
958 .hg/cache/rbc-names-v1: size=14, sha256=d376f7eea9a7e28fac6470e78dae753c81a5543c9ad436e96999590e004a281c
958 .hg/cache/rbc-names-v1: size=14, sha256=d376f7eea9a7e28fac6470e78dae753c81a5543c9ad436e96999590e004a281c
959 .hg/cache/rbc-revs-v1: size=24, sha256=ec89032fd4e66e7282cb6e403848c681a855a9c36c6b44d19179218553b78779
959 .hg/cache/rbc-revs-v1: size=24, sha256=ec89032fd4e66e7282cb6e403848c681a855a9c36c6b44d19179218553b78779
960 #endif
960 #endif
961
961
962 $ cd ..
962 $ cd ..
963
963
964 Test to make sure that `--close-branch` only works on a branch head:
964 Test to make sure that `--close-branch` only works on a branch head:
965 --------------------------------------------------------------------
965 --------------------------------------------------------------------
966 $ hg init closebranch
966 $ hg init closebranch
967 $ cd closebranch
967 $ cd closebranch
968 $ for ch in a b c; do
968 $ for ch in a b c; do
969 > echo $ch > $ch
969 > echo $ch > $ch
970 > hg add $ch
970 > hg add $ch
971 > hg ci -m "added "$ch
971 > hg ci -m "added "$ch
972 > done;
972 > done;
973
973
974 $ hg up -r "desc('added b')"
974 $ hg up -r "desc('added b')"
975 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
975 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
976
976
977 trying to close branch from a cset which is not a branch head
977 trying to close branch from a cset which is not a branch head
978 it should abort:
978 it should abort:
979 $ hg ci -m "closing branch" --close-branch
979 $ hg ci -m "closing branch" --close-branch
980 abort: can only close branch heads
980 abort: can only close branch heads
981 (use --force-close-branch to close branch from a non-head changeset)
981 (use --force-close-branch to close branch from a non-head changeset)
982 [10]
982 [10]
983
983
984 $ hg up 0
984 $ hg up 0
985 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
985 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
986 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
986 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
987 o 2: 155349b645be added c
987 o 2: 155349b645be added c
988 | default
988 | default
989 |
989 |
990 o 1: 5f6d8a4bf34a added b
990 o 1: 5f6d8a4bf34a added b
991 | default
991 | default
992 |
992 |
993 @ 0: 9092f1db7931 added a
993 @ 0: 9092f1db7931 added a
994 default
994 default
995
995
996 Test --force-close-branch to close a branch from a non-head changeset:
996 Test --force-close-branch to close a branch from a non-head changeset:
997 ---------------------------------------------------------------------
997 ---------------------------------------------------------------------
998
998
999 $ hg show stack --config extensions.show=
999 $ hg show stack --config extensions.show=
1000 o 1553 added c
1000 o 1553 added c
1001 o 5f6d added b
1001 o 5f6d added b
1002 @ 9092 added a
1002 @ 9092 added a
1003
1003
1004 $ hg ci -m "branch closed" --close-branch
1004 $ hg ci -m "branch closed" --close-branch
1005 abort: can only close branch heads
1005 abort: can only close branch heads
1006 (use --force-close-branch to close branch from a non-head changeset)
1006 (use --force-close-branch to close branch from a non-head changeset)
1007 [10]
1007 [10]
1008
1008
1009 $ hg ci -m "branch closed" --force-close-branch
1009 $ hg ci -m "branch closed" --force-close-branch
1010 created new head
1010 created new head
1011 $ cd ..
1011 $ cd ..
1012
1012
1013 Test various special cases for the branchmap
1013 Test various special cases for the branchmap
1014 --------------------------------------------
1014 --------------------------------------------
1015
1015
1016 Basic fork of the same branch
1016 Basic fork of the same branch
1017
1017
1018 $ hg init branchmap-testing1
1018 $ hg init branchmap-testing1
1019 $ cd branchmap-testing1
1019 $ cd branchmap-testing1
1020 $ hg debugbuild '@A . :base . :p1 *base /p1'
1020 $ hg debugbuild '@A . :base . :p1 *base /p1'
1021 $ hg log -G
1021 $ hg log -G
1022 o changeset: 3:71ca9a6d524e
1022 o changeset: 3:71ca9a6d524e
1023 |\ branch: A
1023 |\ branch: A
1024 | | tag: tip
1024 | | tag: tip
1025 | | parent: 2:a3b807b3ff0b
1025 | | parent: 2:a3b807b3ff0b
1026 | | parent: 1:99ba08759bc7
1026 | | parent: 1:99ba08759bc7
1027 | | user: debugbuilddag
1027 | | user: debugbuilddag
1028 | | date: Thu Jan 01 00:00:03 1970 +0000
1028 | | date: Thu Jan 01 00:00:03 1970 +0000
1029 | | summary: r3
1029 | | summary: r3
1030 | |
1030 | |
1031 | o changeset: 2:a3b807b3ff0b
1031 | o changeset: 2:a3b807b3ff0b
1032 | | branch: A
1032 | | branch: A
1033 | | parent: 0:2ab8003a1750
1033 | | parent: 0:2ab8003a1750
1034 | | user: debugbuilddag
1034 | | user: debugbuilddag
1035 | | date: Thu Jan 01 00:00:02 1970 +0000
1035 | | date: Thu Jan 01 00:00:02 1970 +0000
1036 | | summary: r2
1036 | | summary: r2
1037 | |
1037 | |
1038 o | changeset: 1:99ba08759bc7
1038 o | changeset: 1:99ba08759bc7
1039 |/ branch: A
1039 |/ branch: A
1040 | tag: p1
1040 | tag: p1
1041 | user: debugbuilddag
1041 | user: debugbuilddag
1042 | date: Thu Jan 01 00:00:01 1970 +0000
1042 | date: Thu Jan 01 00:00:01 1970 +0000
1043 | summary: r1
1043 | summary: r1
1044 |
1044 |
1045 o changeset: 0:2ab8003a1750
1045 o changeset: 0:2ab8003a1750
1046 branch: A
1046 branch: A
1047 tag: base
1047 tag: base
1048 user: debugbuilddag
1048 user: debugbuilddag
1049 date: Thu Jan 01 00:00:00 1970 +0000
1049 date: Thu Jan 01 00:00:00 1970 +0000
1050 summary: r0
1050 summary: r0
1051
1051
1052 $ hg branches
1052 $ hg branches
1053 A 3:71ca9a6d524e
1053 A 3:71ca9a6d524e
1054 $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone
1054 $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone
1055 adding changesets
1055 adding changesets
1056 adding manifests
1056 adding manifests
1057 adding file changes
1057 adding file changes
1058 added 3 changesets with 0 changes to 0 files (+1 heads)
1058 added 3 changesets with 0 changes to 0 files (+1 heads)
1059 new changesets 2ab8003a1750:a3b807b3ff0b
1059 new changesets 2ab8003a1750:a3b807b3ff0b
1060 updating to branch A
1060 updating to branch A
1061 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1061 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1062 $ cd ../branchmap-testing1-clone
1062 $ cd ../branchmap-testing1-clone
1063 $ hg pull ../branchmap-testing1
1063 $ hg pull ../branchmap-testing1
1064 pulling from ../branchmap-testing1
1064 pulling from ../branchmap-testing1
1065 searching for changes
1065 searching for changes
1066 adding changesets
1066 adding changesets
1067 adding manifests
1067 adding manifests
1068 adding file changes
1068 adding file changes
1069 added 1 changesets with 0 changes to 0 files (-1 heads)
1069 added 1 changesets with 0 changes to 0 files (-1 heads)
1070 new changesets 71ca9a6d524e
1070 new changesets 71ca9a6d524e
1071 (run 'hg update' to get a working copy)
1071 (run 'hg update' to get a working copy)
1072 $ hg branches
1072 $ hg branches
1073 A 3:71ca9a6d524e
1073 A 3:71ca9a6d524e
1074 $ cd ..
1074 $ cd ..
1075
1075
1076 Switching to a different branch and back
1076 Switching to a different branch and back
1077
1077
1078 $ hg init branchmap-testing2
1078 $ hg init branchmap-testing2
1079 $ cd branchmap-testing2
1079 $ cd branchmap-testing2
1080 $ hg debugbuild '@A . @B . @A .'
1080 $ hg debugbuild '@A . @B . @A .'
1081 $ hg log -G
1081 $ hg log -G
1082 o changeset: 2:9699e9f260b5
1082 o changeset: 2:9699e9f260b5
1083 | branch: A
1083 | branch: A
1084 | tag: tip
1084 | tag: tip
1085 | user: debugbuilddag
1085 | user: debugbuilddag
1086 | date: Thu Jan 01 00:00:02 1970 +0000
1086 | date: Thu Jan 01 00:00:02 1970 +0000
1087 | summary: r2
1087 | summary: r2
1088 |
1088 |
1089 o changeset: 1:0bc7d348d965
1089 o changeset: 1:0bc7d348d965
1090 | branch: B
1090 | branch: B
1091 | user: debugbuilddag
1091 | user: debugbuilddag
1092 | date: Thu Jan 01 00:00:01 1970 +0000
1092 | date: Thu Jan 01 00:00:01 1970 +0000
1093 | summary: r1
1093 | summary: r1
1094 |
1094 |
1095 o changeset: 0:2ab8003a1750
1095 o changeset: 0:2ab8003a1750
1096 branch: A
1096 branch: A
1097 user: debugbuilddag
1097 user: debugbuilddag
1098 date: Thu Jan 01 00:00:00 1970 +0000
1098 date: Thu Jan 01 00:00:00 1970 +0000
1099 summary: r0
1099 summary: r0
1100
1100
1101 $ hg branches
1101 $ hg branches
1102 A 2:9699e9f260b5
1102 A 2:9699e9f260b5
1103 B 1:0bc7d348d965 (inactive)
1103 B 1:0bc7d348d965 (inactive)
1104 $ hg clone -r 1 . ../branchmap-testing2-clone
1104 $ hg clone -r 1 . ../branchmap-testing2-clone
1105 adding changesets
1105 adding changesets
1106 adding manifests
1106 adding manifests
1107 adding file changes
1107 adding file changes
1108 added 2 changesets with 0 changes to 0 files
1108 added 2 changesets with 0 changes to 0 files
1109 new changesets 2ab8003a1750:0bc7d348d965
1109 new changesets 2ab8003a1750:0bc7d348d965
1110 updating to branch B
1110 updating to branch B
1111 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1111 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1112 $ cd ../branchmap-testing2-clone
1112 $ cd ../branchmap-testing2-clone
1113 $ hg pull ../branchmap-testing2
1113 $ hg pull ../branchmap-testing2
1114 pulling from ../branchmap-testing2
1114 pulling from ../branchmap-testing2
1115 searching for changes
1115 searching for changes
1116 adding changesets
1116 adding changesets
1117 adding manifests
1117 adding manifests
1118 adding file changes
1118 adding file changes
1119 added 1 changesets with 0 changes to 0 files
1119 added 1 changesets with 0 changes to 0 files
1120 new changesets 9699e9f260b5
1120 new changesets 9699e9f260b5
1121 (run 'hg update' to get a working copy)
1121 (run 'hg update' to get a working copy)
1122 $ hg branches
1122 $ hg branches
1123 A 2:9699e9f260b5
1123 A 2:9699e9f260b5
1124 B 1:0bc7d348d965 (inactive)
1124 B 1:0bc7d348d965 (inactive)
1125 $ cd ..
1125 $ cd ..
1126
1126
1127 A fork on a branch switching to a different branch and back
1127 A fork on a branch switching to a different branch and back
1128 is still collecting the fork.
1128 is still collecting the fork.
1129
1129
1130 $ hg init branchmap-testing3
1130 $ hg init branchmap-testing3
1131 $ cd branchmap-testing3
1131 $ cd branchmap-testing3
1132 $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1'
1132 $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1'
1133 $ hg log -G
1133 $ hg log -G
1134 o changeset: 4:3614a1711d23
1134 o changeset: 4:3614a1711d23
1135 |\ branch: A
1135 |\ branch: A
1136 | | tag: tip
1136 | | tag: tip
1137 | | parent: 3:e9c8abcf65aa
1137 | | parent: 3:e9c8abcf65aa
1138 | | parent: 1:99ba08759bc7
1138 | | parent: 1:99ba08759bc7
1139 | | user: debugbuilddag
1139 | | user: debugbuilddag
1140 | | date: Thu Jan 01 00:00:04 1970 +0000
1140 | | date: Thu Jan 01 00:00:04 1970 +0000
1141 | | summary: r4
1141 | | summary: r4
1142 | |
1142 | |
1143 | o changeset: 3:e9c8abcf65aa
1143 | o changeset: 3:e9c8abcf65aa
1144 | | branch: B
1144 | | branch: B
1145 | | user: debugbuilddag
1145 | | user: debugbuilddag
1146 | | date: Thu Jan 01 00:00:03 1970 +0000
1146 | | date: Thu Jan 01 00:00:03 1970 +0000
1147 | | summary: r3
1147 | | summary: r3
1148 | |
1148 | |
1149 | o changeset: 2:a3b807b3ff0b
1149 | o changeset: 2:a3b807b3ff0b
1150 | | branch: A
1150 | | branch: A
1151 | | parent: 0:2ab8003a1750
1151 | | parent: 0:2ab8003a1750
1152 | | user: debugbuilddag
1152 | | user: debugbuilddag
1153 | | date: Thu Jan 01 00:00:02 1970 +0000
1153 | | date: Thu Jan 01 00:00:02 1970 +0000
1154 | | summary: r2
1154 | | summary: r2
1155 | |
1155 | |
1156 o | changeset: 1:99ba08759bc7
1156 o | changeset: 1:99ba08759bc7
1157 |/ branch: A
1157 |/ branch: A
1158 | tag: p1
1158 | tag: p1
1159 | user: debugbuilddag
1159 | user: debugbuilddag
1160 | date: Thu Jan 01 00:00:01 1970 +0000
1160 | date: Thu Jan 01 00:00:01 1970 +0000
1161 | summary: r1
1161 | summary: r1
1162 |
1162 |
1163 o changeset: 0:2ab8003a1750
1163 o changeset: 0:2ab8003a1750
1164 branch: A
1164 branch: A
1165 tag: base
1165 tag: base
1166 user: debugbuilddag
1166 user: debugbuilddag
1167 date: Thu Jan 01 00:00:00 1970 +0000
1167 date: Thu Jan 01 00:00:00 1970 +0000
1168 summary: r0
1168 summary: r0
1169
1169
1170 $ hg branches
1170 $ hg branches
1171 A 4:3614a1711d23
1171 A 4:3614a1711d23
1172 B 3:e9c8abcf65aa (inactive)
1172 B 3:e9c8abcf65aa (inactive)
1173 $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone
1173 $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone
1174 adding changesets
1174 adding changesets
1175 adding manifests
1175 adding manifests
1176 adding file changes
1176 adding file changes
1177 added 4 changesets with 0 changes to 0 files (+1 heads)
1177 added 4 changesets with 0 changes to 0 files (+1 heads)
1178 new changesets 2ab8003a1750:e9c8abcf65aa
1178 new changesets 2ab8003a1750:e9c8abcf65aa
1179 updating to branch A
1179 updating to branch A
1180 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1180 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1181 $ cd ../branchmap-testing3-clone
1181 $ cd ../branchmap-testing3-clone
1182 $ hg pull ../branchmap-testing3
1182 $ hg pull ../branchmap-testing3
1183 pulling from ../branchmap-testing3
1183 pulling from ../branchmap-testing3
1184 searching for changes
1184 searching for changes
1185 adding changesets
1185 adding changesets
1186 adding manifests
1186 adding manifests
1187 adding file changes
1187 adding file changes
1188 added 1 changesets with 0 changes to 0 files (-1 heads)
1188 added 1 changesets with 0 changes to 0 files (-1 heads)
1189 new changesets 3614a1711d23
1189 new changesets 3614a1711d23
1190 (run 'hg update' to get a working copy)
1190 (run 'hg update' to get a working copy)
1191 $ hg branches
1191 $ hg branches
1192 A 4:3614a1711d23
1192 A 4:3614a1711d23
1193 B 3:e9c8abcf65aa (inactive)
1193 B 3:e9c8abcf65aa (inactive)
1194 $ cd ..
1194 $ cd ..
1195
1195
1196 Intermediary parents are on different branches.
1196 Intermediary parents are on different branches.
1197
1197
1198 $ hg init branchmap-testing4
1198 $ hg init branchmap-testing4
1199 $ cd branchmap-testing4
1199 $ cd branchmap-testing4
1200 $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1'
1200 $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1'
1201 $ hg log -G
1201 $ hg log -G
1202 o changeset: 4:4bf67499b70a
1202 o changeset: 4:4bf67499b70a
1203 |\ branch: A
1203 |\ branch: A
1204 | | tag: tip
1204 | | tag: tip
1205 | | parent: 3:4a546028fa8f
1205 | | parent: 3:4a546028fa8f
1206 | | parent: 1:0bc7d348d965
1206 | | parent: 1:0bc7d348d965
1207 | | user: debugbuilddag
1207 | | user: debugbuilddag
1208 | | date: Thu Jan 01 00:00:04 1970 +0000
1208 | | date: Thu Jan 01 00:00:04 1970 +0000
1209 | | summary: r4
1209 | | summary: r4
1210 | |
1210 | |
1211 | o changeset: 3:4a546028fa8f
1211 | o changeset: 3:4a546028fa8f
1212 | | branch: C
1212 | | branch: C
1213 | | user: debugbuilddag
1213 | | user: debugbuilddag
1214 | | date: Thu Jan 01 00:00:03 1970 +0000
1214 | | date: Thu Jan 01 00:00:03 1970 +0000
1215 | | summary: r3
1215 | | summary: r3
1216 | |
1216 | |
1217 | o changeset: 2:a3b807b3ff0b
1217 | o changeset: 2:a3b807b3ff0b
1218 | | branch: A
1218 | | branch: A
1219 | | parent: 0:2ab8003a1750
1219 | | parent: 0:2ab8003a1750
1220 | | user: debugbuilddag
1220 | | user: debugbuilddag
1221 | | date: Thu Jan 01 00:00:02 1970 +0000
1221 | | date: Thu Jan 01 00:00:02 1970 +0000
1222 | | summary: r2
1222 | | summary: r2
1223 | |
1223 | |
1224 o | changeset: 1:0bc7d348d965
1224 o | changeset: 1:0bc7d348d965
1225 |/ branch: B
1225 |/ branch: B
1226 | tag: p1
1226 | tag: p1
1227 | user: debugbuilddag
1227 | user: debugbuilddag
1228 | date: Thu Jan 01 00:00:01 1970 +0000
1228 | date: Thu Jan 01 00:00:01 1970 +0000
1229 | summary: r1
1229 | summary: r1
1230 |
1230 |
1231 o changeset: 0:2ab8003a1750
1231 o changeset: 0:2ab8003a1750
1232 branch: A
1232 branch: A
1233 tag: base
1233 tag: base
1234 user: debugbuilddag
1234 user: debugbuilddag
1235 date: Thu Jan 01 00:00:00 1970 +0000
1235 date: Thu Jan 01 00:00:00 1970 +0000
1236 summary: r0
1236 summary: r0
1237
1237
1238 $ hg branches
1238 $ hg branches
1239 A 4:4bf67499b70a
1239 A 4:4bf67499b70a
1240 C 3:4a546028fa8f (inactive)
1240 C 3:4a546028fa8f (inactive)
1241 B 1:0bc7d348d965 (inactive)
1241 B 1:0bc7d348d965 (inactive)
1242 $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone
1242 $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone
1243 adding changesets
1243 adding changesets
1244 adding manifests
1244 adding manifests
1245 adding file changes
1245 adding file changes
1246 added 4 changesets with 0 changes to 0 files (+1 heads)
1246 added 4 changesets with 0 changes to 0 files (+1 heads)
1247 new changesets 2ab8003a1750:4a546028fa8f
1247 new changesets 2ab8003a1750:4a546028fa8f
1248 updating to branch B
1248 updating to branch B
1249 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1249 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1250 $ cd ../branchmap-testing4-clone
1250 $ cd ../branchmap-testing4-clone
1251 $ hg pull ../branchmap-testing4
1251 $ hg pull ../branchmap-testing4
1252 pulling from ../branchmap-testing4
1252 pulling from ../branchmap-testing4
1253 searching for changes
1253 searching for changes
1254 adding changesets
1254 adding changesets
1255 adding manifests
1255 adding manifests
1256 adding file changes
1256 adding file changes
1257 added 1 changesets with 0 changes to 0 files (-1 heads)
1257 added 1 changesets with 0 changes to 0 files (-1 heads)
1258 new changesets 4bf67499b70a
1258 new changesets 4bf67499b70a
1259 (run 'hg update' to get a working copy)
1259 (run 'hg update' to get a working copy)
1260 $ hg branches
1260 $ hg branches
1261 A 4:4bf67499b70a
1261 A 4:4bf67499b70a
1262 C 3:4a546028fa8f (inactive)
1262 C 3:4a546028fa8f (inactive)
1263 B 1:0bc7d348d965 (inactive)
1263 B 1:0bc7d348d965 (inactive)
1264 $ cd ..
1264 $ cd ..
1265
1265
1266 Check that the cache are not written too early
1266 Check that the cache are not written too early
1267 ----------------------------------------------
1267 ----------------------------------------------
1268
1268
1269 $ hg log -R branchmap-testing1 -G
1269 $ hg log -R branchmap-testing1 -G
1270 o changeset: 3:71ca9a6d524e
1270 o changeset: 3:71ca9a6d524e
1271 |\ branch: A
1271 |\ branch: A
1272 | | tag: tip
1272 | | tag: tip
1273 | | parent: 2:a3b807b3ff0b
1273 | | parent: 2:a3b807b3ff0b
1274 | | parent: 1:99ba08759bc7
1274 | | parent: 1:99ba08759bc7
1275 | | user: debugbuilddag
1275 | | user: debugbuilddag
1276 | | date: Thu Jan 01 00:00:03 1970 +0000
1276 | | date: Thu Jan 01 00:00:03 1970 +0000
1277 | | summary: r3
1277 | | summary: r3
1278 | |
1278 | |
1279 | o changeset: 2:a3b807b3ff0b
1279 | o changeset: 2:a3b807b3ff0b
1280 | | branch: A
1280 | | branch: A
1281 | | parent: 0:2ab8003a1750
1281 | | parent: 0:2ab8003a1750
1282 | | user: debugbuilddag
1282 | | user: debugbuilddag
1283 | | date: Thu Jan 01 00:00:02 1970 +0000
1283 | | date: Thu Jan 01 00:00:02 1970 +0000
1284 | | summary: r2
1284 | | summary: r2
1285 | |
1285 | |
1286 o | changeset: 1:99ba08759bc7
1286 o | changeset: 1:99ba08759bc7
1287 |/ branch: A
1287 |/ branch: A
1288 | tag: p1
1288 | tag: p1
1289 | user: debugbuilddag
1289 | user: debugbuilddag
1290 | date: Thu Jan 01 00:00:01 1970 +0000
1290 | date: Thu Jan 01 00:00:01 1970 +0000
1291 | summary: r1
1291 | summary: r1
1292 |
1292 |
1293 o changeset: 0:2ab8003a1750
1293 o changeset: 0:2ab8003a1750
1294 branch: A
1294 branch: A
1295 tag: base
1295 tag: base
1296 user: debugbuilddag
1296 user: debugbuilddag
1297 date: Thu Jan 01 00:00:00 1970 +0000
1297 date: Thu Jan 01 00:00:00 1970 +0000
1298 summary: r0
1298 summary: r0
1299
1299
1300 $ hg bundle -R branchmap-testing1 --base 1 bundle.hg --rev 'head()'
1300 $ hg bundle -R branchmap-testing1 --base 1 bundle.hg --rev 'head()'
1301 2 changesets found
1301 2 changesets found
1302
1302
1303 Unbundling revision should warm the served cache
1303 Unbundling revision should warm the served cache
1304
1304
1305 $ hg clone branchmap-testing1 --rev 1 branchmap-update-01
1305 $ hg clone branchmap-testing1 --rev 1 branchmap-update-01
1306 adding changesets
1306 adding changesets
1307 adding manifests
1307 adding manifests
1308 adding file changes
1308 adding file changes
1309 added 2 changesets with 0 changes to 0 files
1309 added 2 changesets with 0 changes to 0 files
1310 new changesets 2ab8003a1750:99ba08759bc7
1310 new changesets 2ab8003a1750:99ba08759bc7
1311 updating to branch A
1311 updating to branch A
1312 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1312 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1313 #if v3
1313 #if v3
1314 $ cat branchmap-update-01/.hg/cache/branch3-base
1314 $ cat branchmap-update-01/.hg/cache/branch3-base
1315 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1
1315 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1 topo-mode=pure
1316 A
1316 #else
1317 #else
1317 $ cat branchmap-update-01/.hg/cache/branch2-base
1318 $ cat branchmap-update-01/.hg/cache/branch2-base
1318 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1319 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1319 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1320 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1320 #endif
1321 #endif
1321 $ hg -R branchmap-update-01 unbundle bundle.hg
1322 $ hg -R branchmap-update-01 unbundle bundle.hg
1322 adding changesets
1323 adding changesets
1323 adding manifests
1324 adding manifests
1324 adding file changes
1325 adding file changes
1325 added 2 changesets with 0 changes to 0 files
1326 added 2 changesets with 0 changes to 0 files
1326 new changesets a3b807b3ff0b:71ca9a6d524e (2 drafts)
1327 new changesets a3b807b3ff0b:71ca9a6d524e (2 drafts)
1327 (run 'hg update' to get a working copy)
1328 (run 'hg update' to get a working copy)
1328 #if v3
1329 #if v3
1329 $ cat branchmap-update-01/.hg/cache/branch3-served
1330 $ cat branchmap-update-01/.hg/cache/branch3-served
1330 tip-node=71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 tip-rev=3
1331 tip-node=71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 tip-rev=3 topo-mode=pure
1332 A
1331 #else
1333 #else
1332 $ cat branchmap-update-01/.hg/cache/branch2-served
1334 $ cat branchmap-update-01/.hg/cache/branch2-served
1333 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 3
1335 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 3
1334 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 o A
1336 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 o A
1335 #endif
1337 #endif
1336
1338
1337 aborted Unbundle should not update the on disk cache
1339 aborted Unbundle should not update the on disk cache
1338
1340
1339 $ cat >> simplehook.py << EOF
1341 $ cat >> simplehook.py << EOF
1340 > import sys
1342 > import sys
1341 > from mercurial import node
1343 > from mercurial import node
1342 > from mercurial import branchmap
1344 > from mercurial import branchmap
1343 > def hook(ui, repo, *args, **kwargs):
1345 > def hook(ui, repo, *args, **kwargs):
1344 > s = repo.filtered(b"served")
1346 > s = repo.filtered(b"served")
1345 > s.branchmap()
1347 > s.branchmap()
1346 > return 1
1348 > return 1
1347 > EOF
1349 > EOF
1348 $ hg clone branchmap-testing1 --rev 1 branchmap-update-02
1350 $ hg clone branchmap-testing1 --rev 1 branchmap-update-02
1349 adding changesets
1351 adding changesets
1350 adding manifests
1352 adding manifests
1351 adding file changes
1353 adding file changes
1352 added 2 changesets with 0 changes to 0 files
1354 added 2 changesets with 0 changes to 0 files
1353 new changesets 2ab8003a1750:99ba08759bc7
1355 new changesets 2ab8003a1750:99ba08759bc7
1354 updating to branch A
1356 updating to branch A
1355 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1357 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1356
1358
1357 #if v3
1359 #if v3
1358 $ cat branchmap-update-02/.hg/cache/branch3-base
1360 $ cat branchmap-update-02/.hg/cache/branch3-base
1359 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1
1361 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1 topo-mode=pure
1362 A
1360 #else
1363 #else
1361 $ cat branchmap-update-02/.hg/cache/branch2-base
1364 $ cat branchmap-update-02/.hg/cache/branch2-base
1362 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1365 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1363 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1366 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1364 #endif
1367 #endif
1365 $ hg -R branchmap-update-02 unbundle bundle.hg --config "hooks.pretxnclose=python:$TESTTMP/simplehook.py:hook"
1368 $ hg -R branchmap-update-02 unbundle bundle.hg --config "hooks.pretxnclose=python:$TESTTMP/simplehook.py:hook"
1366 adding changesets
1369 adding changesets
1367 adding manifests
1370 adding manifests
1368 adding file changes
1371 adding file changes
1369 transaction abort!
1372 transaction abort!
1370 rollback completed
1373 rollback completed
1371 abort: pretxnclose hook failed
1374 abort: pretxnclose hook failed
1372 [40]
1375 [40]
1373 #if v3
1376 #if v3
1374 $ cat branchmap-update-02/.hg/cache/branch3-base
1377 $ cat branchmap-update-02/.hg/cache/branch3-base
1375 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1
1378 tip-node=99ba08759bc7f6fdbe5304e83d0387f35c082479 tip-rev=1 topo-mode=pure
1379 A
1376 #else
1380 #else
1377 $ cat branchmap-update-02/.hg/cache/branch2-base
1381 $ cat branchmap-update-02/.hg/cache/branch2-base
1378 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1382 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1379 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1383 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1380 #endif
1384 #endif
General Comments 0
You need to be logged in to leave comments. Login now