##// END OF EJS Templates
branchmap: avoid ancestor computations in absence of non-continous branches...
Joerg Sonnenberger -
r46872:f5d7df72 default draft
parent child Browse files
Show More
@@ -1,765 +1,814 b''
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import struct
10 import struct
11
11
12 from .node import (
12 from .node import (
13 bin,
13 bin,
14 hex,
14 hex,
15 nullid,
15 nullid,
16 nullrev,
16 nullrev,
17 )
17 )
18 from . import (
18 from . import (
19 encoding,
19 encoding,
20 error,
20 error,
21 pycompat,
21 pycompat,
22 scmutil,
22 scmutil,
23 util,
23 util,
24 )
24 )
25 from .utils import (
25 from .utils import (
26 repoviewutil,
26 repoviewutil,
27 stringutil,
27 stringutil,
28 )
28 )
29
29
30 if pycompat.TYPE_CHECKING:
30 if pycompat.TYPE_CHECKING:
31 from typing import (
31 from typing import (
32 Any,
32 Any,
33 Callable,
33 Callable,
34 Dict,
34 Dict,
35 Iterable,
35 Iterable,
36 List,
36 List,
37 Optional,
37 Optional,
38 Set,
38 Set,
39 Tuple,
39 Tuple,
40 Union,
40 Union,
41 )
41 )
42
42
43 assert any(
43 assert any(
44 (
44 (
45 Any,
45 Any,
46 Callable,
46 Callable,
47 Dict,
47 Dict,
48 Iterable,
48 Iterable,
49 List,
49 List,
50 Optional,
50 Optional,
51 Set,
51 Set,
52 Tuple,
52 Tuple,
53 Union,
53 Union,
54 )
54 )
55 )
55 )
56
56
57 subsettable = repoviewutil.subsettable
57 subsettable = repoviewutil.subsettable
58
58
59 calcsize = struct.calcsize
59 calcsize = struct.calcsize
60 pack_into = struct.pack_into
60 pack_into = struct.pack_into
61 unpack_from = struct.unpack_from
61 unpack_from = struct.unpack_from
62
62
63
63
64 class BranchMapCache(object):
64 class BranchMapCache(object):
65 """mapping of filtered views of repo with their branchcache"""
65 """mapping of filtered views of repo with their branchcache"""
66
66
67 def __init__(self):
67 def __init__(self):
68 self._per_filter = {}
68 self._per_filter = {}
69
69
70 def __getitem__(self, repo):
70 def __getitem__(self, repo):
71 self.updatecache(repo)
71 self.updatecache(repo)
72 return self._per_filter[repo.filtername]
72 return self._per_filter[repo.filtername]
73
73
74 def updatecache(self, repo):
74 def updatecache(self, repo):
75 """Update the cache for the given filtered view on a repository"""
75 """Update the cache for the given filtered view on a repository"""
76 # This can trigger updates for the caches for subsets of the filtered
76 # This can trigger updates for the caches for subsets of the filtered
77 # view, e.g. when there is no cache for this filtered view or the cache
77 # view, e.g. when there is no cache for this filtered view or the cache
78 # is stale.
78 # is stale.
79
79
80 cl = repo.changelog
80 cl = repo.changelog
81 filtername = repo.filtername
81 filtername = repo.filtername
82 bcache = self._per_filter.get(filtername)
82 bcache = self._per_filter.get(filtername)
83 if bcache is None or not bcache.validfor(repo):
83 if bcache is None or not bcache.validfor(repo):
84 # cache object missing or cache object stale? Read from disk
84 # cache object missing or cache object stale? Read from disk
85 bcache = branchcache.fromfile(repo)
85 bcache = branchcache.fromfile(repo)
86
86
87 revs = []
87 revs = []
88 if bcache is None:
88 if bcache is None:
89 # no (fresh) cache available anymore, perhaps we can re-use
89 # no (fresh) cache available anymore, perhaps we can re-use
90 # the cache for a subset, then extend that to add info on missing
90 # the cache for a subset, then extend that to add info on missing
91 # revisions.
91 # revisions.
92 subsetname = subsettable.get(filtername)
92 subsetname = subsettable.get(filtername)
93 if subsetname is not None:
93 if subsetname is not None:
94 subset = repo.filtered(subsetname)
94 subset = repo.filtered(subsetname)
95 bcache = self[subset].copy()
95 bcache = self[subset].copy()
96 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
96 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
97 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
97 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
98 else:
98 else:
99 # nothing to fall back on, start empty.
99 # nothing to fall back on, start empty.
100 bcache = branchcache()
100 bcache = branchcache()
101
101
102 revs.extend(cl.revs(start=bcache.tiprev + 1))
102 revs.extend(cl.revs(start=bcache.tiprev + 1))
103 if revs:
103 if revs:
104 bcache.update(repo, revs)
104 bcache.update(repo, revs)
105
105
106 assert bcache.validfor(repo), filtername
106 assert bcache.validfor(repo), filtername
107 self._per_filter[repo.filtername] = bcache
107 self._per_filter[repo.filtername] = bcache
108
108
109 def replace(self, repo, remotebranchmap):
109 def replace(self, repo, remotebranchmap):
110 """Replace the branchmap cache for a repo with a branch mapping.
110 """Replace the branchmap cache for a repo with a branch mapping.
111
111
112 This is likely only called during clone with a branch map from a
112 This is likely only called during clone with a branch map from a
113 remote.
113 remote.
114
114
115 """
115 """
116 cl = repo.changelog
116 cl = repo.changelog
117 clrev = cl.rev
117 clrev = cl.rev
118 clbranchinfo = cl.branchinfo
118 clbranchinfo = cl.branchinfo
119 rbheads = []
119 rbheads = []
120 closed = set()
120 closed = set()
121 for bheads in pycompat.itervalues(remotebranchmap):
121 for bheads in pycompat.itervalues(remotebranchmap):
122 rbheads += bheads
122 rbheads += bheads
123 for h in bheads:
123 for h in bheads:
124 r = clrev(h)
124 r = clrev(h)
125 b, c = clbranchinfo(r)
125 b, c = clbranchinfo(r)
126 if c:
126 if c:
127 closed.add(h)
127 closed.add(h)
128
128
129 if rbheads:
129 if rbheads:
130 rtiprev = max((int(clrev(node)) for node in rbheads))
130 rtiprev = max((int(clrev(node)) for node in rbheads))
131 cache = branchcache(
131 cache = branchcache(
132 remotebranchmap,
132 remotebranchmap,
133 repo[rtiprev].node(),
133 repo[rtiprev].node(),
134 rtiprev,
134 rtiprev,
135 closednodes=closed,
135 closednodes=closed,
136 )
136 )
137
137
138 # Try to stick it as low as possible
138 # Try to stick it as low as possible
139 # filter above served are unlikely to be fetch from a clone
139 # filter above served are unlikely to be fetch from a clone
140 for candidate in (b'base', b'immutable', b'served'):
140 for candidate in (b'base', b'immutable', b'served'):
141 rview = repo.filtered(candidate)
141 rview = repo.filtered(candidate)
142 if cache.validfor(rview):
142 if cache.validfor(rview):
143 self._per_filter[candidate] = cache
143 self._per_filter[candidate] = cache
144 cache.write(rview)
144 cache.write(rview)
145 return
145 return
146
146
147 def clear(self):
147 def clear(self):
148 self._per_filter.clear()
148 self._per_filter.clear()
149
149
150
150
151 def _unknownnode(node):
151 def _unknownnode(node):
152 """raises ValueError when branchcache found a node which does not exists"""
152 """raises ValueError when branchcache found a node which does not exists"""
153 raise ValueError('node %s does not exist' % pycompat.sysstr(hex(node)))
153 raise ValueError('node %s does not exist' % pycompat.sysstr(hex(node)))
154
154
155
155
156 def _branchcachedesc(repo):
156 def _branchcachedesc(repo):
157 if repo.filtername is not None:
157 if repo.filtername is not None:
158 return b'branch cache (%s)' % repo.filtername
158 return b'branch cache (%s)' % repo.filtername
159 else:
159 else:
160 return b'branch cache'
160 return b'branch cache'
161
161
162
162
163 class branchcache(object):
163 class branchcache(object):
164 """A dict like object that hold branches heads cache.
164 """A dict like object that hold branches heads cache.
165
165
166 This cache is used to avoid costly computations to determine all the
166 This cache is used to avoid costly computations to determine all the
167 branch heads of a repo.
167 branch heads of a repo.
168
168
169 The cache is serialized on disk in the following format:
169 The cache is serialized on disk in the following format:
170
170
171 <tip hex node> <tip rev number> [optional filtered repo hex hash]
171 <tip hex node> <tip rev number> [optional filtered repo hex hash]
172 <branch head hex node> <open/closed state> <branch name>
172 <branch head hex node> <open/closed state> <branch name>
173 <branch head hex node> <open/closed state> <branch name>
173 <branch head hex node> <open/closed state> <branch name>
174 ...
174 ...
175
175
176 The first line is used to check if the cache is still valid. If the
176 The first line is used to check if the cache is still valid. If the
177 branch cache is for a filtered repo view, an optional third hash is
177 branch cache is for a filtered repo view, an optional third hash is
178 included that hashes the hashes of all filtered revisions.
178 included that hashes the hashes of all filtered revisions.
179
179
180 The open/closed state is represented by a single letter 'o' or 'c'.
180 The open/closed state is represented by a single letter 'o' or 'c'.
181 This field can be used to avoid changelog reads when determining if a
181 This field can be used to avoid changelog reads when determining if a
182 branch head closes a branch or not.
182 branch head closes a branch or not.
183 """
183 """
184
184
185 def __init__(
185 def __init__(
186 self,
186 self,
187 entries=(),
187 entries=(),
188 tipnode=nullid,
188 tipnode=nullid,
189 tiprev=nullrev,
189 tiprev=nullrev,
190 filteredhash=None,
190 filteredhash=None,
191 closednodes=None,
191 closednodes=None,
192 hasnode=None,
192 hasnode=None,
193 ):
193 ):
194 # type: (Union[Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]], bytes, int, Optional[bytes], Optional[Set[bytes]], Optional[Callable[[bytes], bool]]) -> None
194 # type: (Union[Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]], bytes, int, Optional[bytes], Optional[Set[bytes]], Optional[Callable[[bytes], bool]]) -> None
195 """hasnode is a function which can be used to verify whether changelog
195 """hasnode is a function which can be used to verify whether changelog
196 has a given node or not. If it's not provided, we assume that every node
196 has a given node or not. If it's not provided, we assume that every node
197 we have exists in changelog"""
197 we have exists in changelog"""
198 self.tipnode = tipnode
198 self.tipnode = tipnode
199 self.tiprev = tiprev
199 self.tiprev = tiprev
200 self.filteredhash = filteredhash
200 self.filteredhash = filteredhash
201 # closednodes is a set of nodes that close their branch. If the branch
201 # closednodes is a set of nodes that close their branch. If the branch
202 # cache has been updated, it may contain nodes that are no longer
202 # cache has been updated, it may contain nodes that are no longer
203 # heads.
203 # heads.
204 if closednodes is None:
204 if closednodes is None:
205 self._closednodes = set()
205 self._closednodes = set()
206 else:
206 else:
207 self._closednodes = closednodes
207 self._closednodes = closednodes
208 self._entries = dict(entries)
208 self._entries = dict(entries)
209 # whether closed nodes are verified or not
209 # whether closed nodes are verified or not
210 self._closedverified = False
210 self._closedverified = False
211 # branches for which nodes are verified
211 # branches for which nodes are verified
212 self._verifiedbranches = set()
212 self._verifiedbranches = set()
213 self._hasnode = hasnode
213 self._hasnode = hasnode
214 if self._hasnode is None:
214 if self._hasnode is None:
215 self._hasnode = lambda x: True
215 self._hasnode = lambda x: True
216
216
217 def _verifyclosed(self):
217 def _verifyclosed(self):
218 """ verify the closed nodes we have """
218 """ verify the closed nodes we have """
219 if self._closedverified:
219 if self._closedverified:
220 return
220 return
221 for node in self._closednodes:
221 for node in self._closednodes:
222 if not self._hasnode(node):
222 if not self._hasnode(node):
223 _unknownnode(node)
223 _unknownnode(node)
224
224
225 self._closedverified = True
225 self._closedverified = True
226
226
227 def _verifybranch(self, branch):
227 def _verifybranch(self, branch):
228 """ verify head nodes for the given branch. """
228 """ verify head nodes for the given branch. """
229 if branch not in self._entries or branch in self._verifiedbranches:
229 if branch not in self._entries or branch in self._verifiedbranches:
230 return
230 return
231 for n in self._entries[branch]:
231 for n in self._entries[branch]:
232 if not self._hasnode(n):
232 if not self._hasnode(n):
233 _unknownnode(n)
233 _unknownnode(n)
234
234
235 self._verifiedbranches.add(branch)
235 self._verifiedbranches.add(branch)
236
236
237 def _verifyall(self):
237 def _verifyall(self):
238 """ verifies nodes of all the branches """
238 """ verifies nodes of all the branches """
239 needverification = set(self._entries.keys()) - self._verifiedbranches
239 needverification = set(self._entries.keys()) - self._verifiedbranches
240 for b in needverification:
240 for b in needverification:
241 self._verifybranch(b)
241 self._verifybranch(b)
242
242
243 def __iter__(self):
243 def __iter__(self):
244 return iter(self._entries)
244 return iter(self._entries)
245
245
246 def __setitem__(self, key, value):
246 def __setitem__(self, key, value):
247 self._entries[key] = value
247 self._entries[key] = value
248
248
249 def __getitem__(self, key):
249 def __getitem__(self, key):
250 self._verifybranch(key)
250 self._verifybranch(key)
251 return self._entries[key]
251 return self._entries[key]
252
252
253 def __contains__(self, key):
253 def __contains__(self, key):
254 self._verifybranch(key)
254 self._verifybranch(key)
255 return key in self._entries
255 return key in self._entries
256
256
257 def iteritems(self):
257 def iteritems(self):
258 for k, v in pycompat.iteritems(self._entries):
258 for k, v in pycompat.iteritems(self._entries):
259 self._verifybranch(k)
259 self._verifybranch(k)
260 yield k, v
260 yield k, v
261
261
262 items = iteritems
262 items = iteritems
263
263
264 def hasbranch(self, label):
264 def hasbranch(self, label):
265 """ checks whether a branch of this name exists or not """
265 """ checks whether a branch of this name exists or not """
266 self._verifybranch(label)
266 self._verifybranch(label)
267 return label in self._entries
267 return label in self._entries
268
268
269 @classmethod
269 @classmethod
270 def fromfile(cls, repo):
270 def fromfile(cls, repo):
271 f = None
271 f = None
272 try:
272 try:
273 f = repo.cachevfs(cls._filename(repo))
273 f = repo.cachevfs(cls._filename(repo))
274 lineiter = iter(f)
274 lineiter = iter(f)
275 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2)
275 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2)
276 last, lrev = cachekey[:2]
276 last, lrev = cachekey[:2]
277 last, lrev = bin(last), int(lrev)
277 last, lrev = bin(last), int(lrev)
278 filteredhash = None
278 filteredhash = None
279 hasnode = repo.changelog.hasnode
279 hasnode = repo.changelog.hasnode
280 if len(cachekey) > 2:
280 if len(cachekey) > 2:
281 filteredhash = bin(cachekey[2])
281 filteredhash = bin(cachekey[2])
282 bcache = cls(
282 bcache = cls(
283 tipnode=last,
283 tipnode=last,
284 tiprev=lrev,
284 tiprev=lrev,
285 filteredhash=filteredhash,
285 filteredhash=filteredhash,
286 hasnode=hasnode,
286 hasnode=hasnode,
287 )
287 )
288 if not bcache.validfor(repo):
288 if not bcache.validfor(repo):
289 # invalidate the cache
289 # invalidate the cache
290 raise ValueError('tip differs')
290 raise ValueError('tip differs')
291 bcache.load(repo, lineiter)
291 bcache.load(repo, lineiter)
292 except (IOError, OSError):
292 except (IOError, OSError):
293 return None
293 return None
294
294
295 except Exception as inst:
295 except Exception as inst:
296 if repo.ui.debugflag:
296 if repo.ui.debugflag:
297 msg = b'invalid %s: %s\n'
297 msg = b'invalid %s: %s\n'
298 repo.ui.debug(
298 repo.ui.debug(
299 msg
299 msg
300 % (
300 % (
301 _branchcachedesc(repo),
301 _branchcachedesc(repo),
302 pycompat.bytestr(
302 pycompat.bytestr(
303 inst
303 inst
304 ), # pytype: disable=wrong-arg-types
304 ), # pytype: disable=wrong-arg-types
305 )
305 )
306 )
306 )
307 bcache = None
307 bcache = None
308
308
309 finally:
309 finally:
310 if f:
310 if f:
311 f.close()
311 f.close()
312
312
313 return bcache
313 return bcache
314
314
315 def load(self, repo, lineiter):
315 def load(self, repo, lineiter):
316 """fully loads the branchcache by reading from the file using the line
316 """fully loads the branchcache by reading from the file using the line
317 iterator passed"""
317 iterator passed"""
318 for line in lineiter:
318 for line in lineiter:
319 line = line.rstrip(b'\n')
319 line = line.rstrip(b'\n')
320 if not line:
320 if not line:
321 continue
321 continue
322 node, state, label = line.split(b" ", 2)
322 node, state, label = line.split(b" ", 2)
323 if state not in b'oc':
323 if state not in b'oc':
324 raise ValueError('invalid branch state')
324 raise ValueError('invalid branch state')
325 label = encoding.tolocal(label.strip())
325 label = encoding.tolocal(label.strip())
326 node = bin(node)
326 node = bin(node)
327 self._entries.setdefault(label, []).append(node)
327 self._entries.setdefault(label, []).append(node)
328 if state == b'c':
328 if state == b'c':
329 self._closednodes.add(node)
329 self._closednodes.add(node)
330
330
331 @staticmethod
331 @staticmethod
332 def _filename(repo):
332 def _filename(repo):
333 """name of a branchcache file for a given repo or repoview"""
333 """name of a branchcache file for a given repo or repoview"""
334 filename = b"branch2"
334 filename = b"branch2"
335 if repo.filtername:
335 if repo.filtername:
336 filename = b'%s-%s' % (filename, repo.filtername)
336 filename = b'%s-%s' % (filename, repo.filtername)
337 return filename
337 return filename
338
338
339 def validfor(self, repo):
339 def validfor(self, repo):
340 """Is the cache content valid regarding a repo
340 """Is the cache content valid regarding a repo
341
341
342 - False when cached tipnode is unknown or if we detect a strip.
342 - False when cached tipnode is unknown or if we detect a strip.
343 - True when cache is up to date or a subset of current repo."""
343 - True when cache is up to date or a subset of current repo."""
344 try:
344 try:
345 return (self.tipnode == repo.changelog.node(self.tiprev)) and (
345 return (self.tipnode == repo.changelog.node(self.tiprev)) and (
346 self.filteredhash == scmutil.filteredhash(repo, self.tiprev)
346 self.filteredhash == scmutil.filteredhash(repo, self.tiprev)
347 )
347 )
348 except IndexError:
348 except IndexError:
349 return False
349 return False
350
350
351 def _branchtip(self, heads):
351 def _branchtip(self, heads):
352 """Return tuple with last open head in heads and false,
352 """Return tuple with last open head in heads and false,
353 otherwise return last closed head and true."""
353 otherwise return last closed head and true."""
354 tip = heads[-1]
354 tip = heads[-1]
355 closed = True
355 closed = True
356 for h in reversed(heads):
356 for h in reversed(heads):
357 if h not in self._closednodes:
357 if h not in self._closednodes:
358 tip = h
358 tip = h
359 closed = False
359 closed = False
360 break
360 break
361 return tip, closed
361 return tip, closed
362
362
363 def branchtip(self, branch):
363 def branchtip(self, branch):
364 """Return the tipmost open head on branch head, otherwise return the
364 """Return the tipmost open head on branch head, otherwise return the
365 tipmost closed head on branch.
365 tipmost closed head on branch.
366 Raise KeyError for unknown branch."""
366 Raise KeyError for unknown branch."""
367 return self._branchtip(self[branch])[0]
367 return self._branchtip(self[branch])[0]
368
368
369 def iteropen(self, nodes):
369 def iteropen(self, nodes):
370 return (n for n in nodes if n not in self._closednodes)
370 return (n for n in nodes if n not in self._closednodes)
371
371
372 def branchheads(self, branch, closed=False):
372 def branchheads(self, branch, closed=False):
373 self._verifybranch(branch)
373 self._verifybranch(branch)
374 heads = self._entries[branch]
374 heads = self._entries[branch]
375 if not closed:
375 if not closed:
376 heads = list(self.iteropen(heads))
376 heads = list(self.iteropen(heads))
377 return heads
377 return heads
378
378
379 def iterbranches(self):
379 def iterbranches(self):
380 for bn, heads in pycompat.iteritems(self):
380 for bn, heads in pycompat.iteritems(self):
381 yield (bn, heads) + self._branchtip(heads)
381 yield (bn, heads) + self._branchtip(heads)
382
382
383 def iterheads(self):
383 def iterheads(self):
384 """ returns all the heads """
384 """ returns all the heads """
385 self._verifyall()
385 self._verifyall()
386 return pycompat.itervalues(self._entries)
386 return pycompat.itervalues(self._entries)
387
387
388 def copy(self):
388 def copy(self):
389 """return an deep copy of the branchcache object"""
389 """return an deep copy of the branchcache object"""
390 return type(self)(
390 return type(self)(
391 self._entries,
391 self._entries,
392 self.tipnode,
392 self.tipnode,
393 self.tiprev,
393 self.tiprev,
394 self.filteredhash,
394 self.filteredhash,
395 self._closednodes,
395 self._closednodes,
396 )
396 )
397
397
398 def write(self, repo):
398 def write(self, repo):
399 try:
399 try:
400 f = repo.cachevfs(self._filename(repo), b"w", atomictemp=True)
400 f = repo.cachevfs(self._filename(repo), b"w", atomictemp=True)
401 cachekey = [hex(self.tipnode), b'%d' % self.tiprev]
401 cachekey = [hex(self.tipnode), b'%d' % self.tiprev]
402 if self.filteredhash is not None:
402 if self.filteredhash is not None:
403 cachekey.append(hex(self.filteredhash))
403 cachekey.append(hex(self.filteredhash))
404 f.write(b" ".join(cachekey) + b'\n')
404 f.write(b" ".join(cachekey) + b'\n')
405 nodecount = 0
405 nodecount = 0
406 for label, nodes in sorted(pycompat.iteritems(self._entries)):
406 for label, nodes in sorted(pycompat.iteritems(self._entries)):
407 label = encoding.fromlocal(label)
407 label = encoding.fromlocal(label)
408 for node in nodes:
408 for node in nodes:
409 nodecount += 1
409 nodecount += 1
410 if node in self._closednodes:
410 if node in self._closednodes:
411 state = b'c'
411 state = b'c'
412 else:
412 else:
413 state = b'o'
413 state = b'o'
414 f.write(b"%s %s %s\n" % (hex(node), state, label))
414 f.write(b"%s %s %s\n" % (hex(node), state, label))
415 f.close()
415 f.close()
416 repo.ui.log(
416 repo.ui.log(
417 b'branchcache',
417 b'branchcache',
418 b'wrote %s with %d labels and %d nodes\n',
418 b'wrote %s with %d labels and %d nodes\n',
419 _branchcachedesc(repo),
419 _branchcachedesc(repo),
420 len(self._entries),
420 len(self._entries),
421 nodecount,
421 nodecount,
422 )
422 )
423 except (IOError, OSError, error.Abort) as inst:
423 except (IOError, OSError, error.Abort) as inst:
424 # Abort may be raised by read only opener, so log and continue
424 # Abort may be raised by read only opener, so log and continue
425 repo.ui.debug(
425 repo.ui.debug(
426 b"couldn't write branch cache: %s\n"
426 b"couldn't write branch cache: %s\n"
427 % stringutil.forcebytestr(inst)
427 % stringutil.forcebytestr(inst)
428 )
428 )
429
429
430 def update(self, repo, revgen):
430 def update(self, repo, revgen):
431 """Given a branchhead cache, self, that may have extra nodes or be
431 """Given a branchhead cache, self, that may have extra nodes or be
432 missing heads, and a generator of nodes that are strictly a superset of
432 missing heads, and a generator of nodes that are strictly a superset of
433 heads missing, this function updates self to be correct.
433 heads missing, this function updates self to be correct.
434 """
434 """
435 starttime = util.timer()
435 starttime = util.timer()
436 cl = repo.changelog
436 cl = repo.changelog
437 # collect new branch entries
437 # collect new branch entries
438 newbranches = {}
438 newbranches = {}
439 getbranchinfo = repo.revbranchcache().branchinfo
439 getbranchinfo = repo.revbranchcache().branchinfo
440 for r in revgen:
440 for r in revgen:
441 branch, closesbranch = getbranchinfo(r)
441 branch, closesbranch = getbranchinfo(r)
442 newbranches.setdefault(branch, []).append(r)
442 newbranches.setdefault(branch, []).append(r)
443 if closesbranch:
443 if closesbranch:
444 self._closednodes.add(cl.node(r))
444 self._closednodes.add(cl.node(r))
445
445
446 # fetch current topological heads to speed up filtering
447 topoheads = set(cl.headrevs())
448
449 # new tip revision which we found after iterating items from new
446 # new tip revision which we found after iterating items from new
450 # branches
447 # branches
451 ntiprev = self.tiprev
448 ntiprev = self.tiprev
452
449
453 # if older branchheads are reachable from new ones, they aren't
450 # Delay fetching the topological heads until they are needed.
454 # really branchheads. Note checking parents is insufficient:
451 # A repository without non-continous branches can skip this part.
455 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
452 topoheads = None
453
454 # If a changeset is visible, its parents must be visible too, so
455 # use the faster unfiltered parent accessor.
456 parentrevs = repo.unfiltered().changelog.parentrevs
457
456 for branch, newheadrevs in pycompat.iteritems(newbranches):
458 for branch, newheadrevs in pycompat.iteritems(newbranches):
459 # For every branch, compute the new branchheads.
460 # A branchhead is a revision such that no descendant is on
461 # the same branch.
462 #
463 # The branchheads are computed iteratively in revision order.
464 # This ensures topological order, i.e. parents are processed
465 # before their children. Ancestors are inclusive here, i.e.
466 # any revision is an ancestor of itself.
467 #
468 # Core observations:
469 # - The current revision is always a branchhead for the
470 # repository up to that point.
471 # - It is the first revision of the branch if and only if
472 # there was no branchhead before. In that case, it is the
473 # only branchhead as there are no possible ancestors on
474 # the same branch.
475 # - If a parent is on the same branch, a branchhead can
476 # only be an ancestor of that parent, if it is parent
477 # itself. Otherwise it would have been removed as ancestor
478 # of that parent before.
479 # - Therefore, if all parents are on the same branch, they
480 # can just be removed from the branchhead set.
481 # - If one parent is on the same branch and the other is not
482 # and there was exactly one branchhead known, the existing
483 # branchhead can only be an ancestor if it is the parent.
484 # Otherwise it would have been removed as ancestor of
485 # the parent before. The other parent therefore can't have
486 # a branchhead as ancestor.
487 # - In all other cases, the parents on different branches
488 # could have a branchhead as ancestor. Those parents are
489 # kept in the "uncertain" set. If all branchheads are also
490 # topological heads, they can't have descendants and further
491 # checks can be skipped. Otherwise, the ancestors of the
492 # "uncertain" set are removed from branchheads.
493 # This computation is heavy and avoided if at all possible.
457 bheads = self._entries.setdefault(branch, [])
494 bheads = self._entries.setdefault(branch, [])
458 bheadset = {cl.rev(node) for node in bheads}
495 bheadset = {cl.rev(node) for node in bheads}
459
496 uncertain = set()
460 # This have been tested True on all internal usage of this function.
497 for newrev in sorted(newheadrevs):
461 # run it again in case of doubt
498 if not bheadset:
462 # assert not (set(bheadrevs) & set(newheadrevs))
499 bheadset.add(newrev)
463 bheadset.update(newheadrevs)
500 continue
464
501
465 # This prunes out two kinds of heads - heads that are superseded by
502 parents = [p for p in parentrevs(newrev) if p != nullrev]
466 # a head in newheadrevs, and newheadrevs that are not heads because
503 samebranch = set()
467 # an existing head is their descendant.
504 otherbranch = set()
468 uncertain = bheadset - topoheads
505 for p in parents:
506 if p in bheadset or getbranchinfo(p)[0] == branch:
507 samebranch.add(p)
508 else:
509 otherbranch.add(p)
510 if otherbranch and not (len(bheadset) == len(samebranch) == 1):
511 uncertain.update(otherbranch)
512 bheadset.difference_update(samebranch)
513 bheadset.add(newrev)
514
469 if uncertain:
515 if uncertain:
470 floorrev = min(uncertain)
516 if topoheads is None:
517 topoheads = set(cl.headrevs())
518 if bheadset - topoheads:
519 floorrev = min(bheadset)
471 ancestors = set(cl.ancestors(newheadrevs, floorrev))
520 ancestors = set(cl.ancestors(newheadrevs, floorrev))
472 bheadset -= ancestors
521 bheadset -= ancestors
473 bheadrevs = sorted(bheadset)
522 bheadrevs = sorted(bheadset)
474 self[branch] = [cl.node(rev) for rev in bheadrevs]
523 self[branch] = [cl.node(rev) for rev in bheadrevs]
475 tiprev = bheadrevs[-1]
524 tiprev = bheadrevs[-1]
476 if tiprev > ntiprev:
525 if tiprev > ntiprev:
477 ntiprev = tiprev
526 ntiprev = tiprev
478
527
479 if ntiprev > self.tiprev:
528 if ntiprev > self.tiprev:
480 self.tiprev = ntiprev
529 self.tiprev = ntiprev
481 self.tipnode = cl.node(ntiprev)
530 self.tipnode = cl.node(ntiprev)
482
531
483 if not self.validfor(repo):
532 if not self.validfor(repo):
484 # cache key are not valid anymore
533 # cache key are not valid anymore
485 self.tipnode = nullid
534 self.tipnode = nullid
486 self.tiprev = nullrev
535 self.tiprev = nullrev
487 for heads in self.iterheads():
536 for heads in self.iterheads():
488 tiprev = max(cl.rev(node) for node in heads)
537 tiprev = max(cl.rev(node) for node in heads)
489 if tiprev > self.tiprev:
538 if tiprev > self.tiprev:
490 self.tipnode = cl.node(tiprev)
539 self.tipnode = cl.node(tiprev)
491 self.tiprev = tiprev
540 self.tiprev = tiprev
492 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
541 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
493
542
494 duration = util.timer() - starttime
543 duration = util.timer() - starttime
495 repo.ui.log(
544 repo.ui.log(
496 b'branchcache',
545 b'branchcache',
497 b'updated %s in %.4f seconds\n',
546 b'updated %s in %.4f seconds\n',
498 _branchcachedesc(repo),
547 _branchcachedesc(repo),
499 duration,
548 duration,
500 )
549 )
501
550
502 self.write(repo)
551 self.write(repo)
503
552
504
553
505 class remotebranchcache(branchcache):
554 class remotebranchcache(branchcache):
506 """Branchmap info for a remote connection, should not write locally"""
555 """Branchmap info for a remote connection, should not write locally"""
507
556
508 def write(self, repo):
557 def write(self, repo):
509 pass
558 pass
510
559
511
560
512 # Revision branch info cache
561 # Revision branch info cache
513
562
514 _rbcversion = b'-v1'
563 _rbcversion = b'-v1'
515 _rbcnames = b'rbc-names' + _rbcversion
564 _rbcnames = b'rbc-names' + _rbcversion
516 _rbcrevs = b'rbc-revs' + _rbcversion
565 _rbcrevs = b'rbc-revs' + _rbcversion
517 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
566 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
518 _rbcrecfmt = b'>4sI'
567 _rbcrecfmt = b'>4sI'
519 _rbcrecsize = calcsize(_rbcrecfmt)
568 _rbcrecsize = calcsize(_rbcrecfmt)
520 _rbcnodelen = 4
569 _rbcnodelen = 4
521 _rbcbranchidxmask = 0x7FFFFFFF
570 _rbcbranchidxmask = 0x7FFFFFFF
522 _rbccloseflag = 0x80000000
571 _rbccloseflag = 0x80000000
523
572
524
573
525 class revbranchcache(object):
574 class revbranchcache(object):
526 """Persistent cache, mapping from revision number to branch name and close.
575 """Persistent cache, mapping from revision number to branch name and close.
527 This is a low level cache, independent of filtering.
576 This is a low level cache, independent of filtering.
528
577
529 Branch names are stored in rbc-names in internal encoding separated by 0.
578 Branch names are stored in rbc-names in internal encoding separated by 0.
530 rbc-names is append-only, and each branch name is only stored once and will
579 rbc-names is append-only, and each branch name is only stored once and will
531 thus have a unique index.
580 thus have a unique index.
532
581
533 The branch info for each revision is stored in rbc-revs as constant size
582 The branch info for each revision is stored in rbc-revs as constant size
534 records. The whole file is read into memory, but it is only 'parsed' on
583 records. The whole file is read into memory, but it is only 'parsed' on
535 demand. The file is usually append-only but will be truncated if repo
584 demand. The file is usually append-only but will be truncated if repo
536 modification is detected.
585 modification is detected.
537 The record for each revision contains the first 4 bytes of the
586 The record for each revision contains the first 4 bytes of the
538 corresponding node hash, and the record is only used if it still matches.
587 corresponding node hash, and the record is only used if it still matches.
539 Even a completely trashed rbc-revs fill thus still give the right result
588 Even a completely trashed rbc-revs fill thus still give the right result
540 while converging towards full recovery ... assuming no incorrectly matching
589 while converging towards full recovery ... assuming no incorrectly matching
541 node hashes.
590 node hashes.
542 The record also contains 4 bytes where 31 bits contains the index of the
591 The record also contains 4 bytes where 31 bits contains the index of the
543 branch and the last bit indicate that it is a branch close commit.
592 branch and the last bit indicate that it is a branch close commit.
544 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
593 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
545 and will grow with it but be 1/8th of its size.
594 and will grow with it but be 1/8th of its size.
546 """
595 """
547
596
548 def __init__(self, repo, readonly=True):
597 def __init__(self, repo, readonly=True):
549 assert repo.filtername is None
598 assert repo.filtername is None
550 self._repo = repo
599 self._repo = repo
551 self._names = [] # branch names in local encoding with static index
600 self._names = [] # branch names in local encoding with static index
552 self._rbcrevs = bytearray()
601 self._rbcrevs = bytearray()
553 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
602 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
554 try:
603 try:
555 bndata = repo.cachevfs.read(_rbcnames)
604 bndata = repo.cachevfs.read(_rbcnames)
556 self._rbcsnameslen = len(bndata) # for verification before writing
605 self._rbcsnameslen = len(bndata) # for verification before writing
557 if bndata:
606 if bndata:
558 self._names = [
607 self._names = [
559 encoding.tolocal(bn) for bn in bndata.split(b'\0')
608 encoding.tolocal(bn) for bn in bndata.split(b'\0')
560 ]
609 ]
561 except (IOError, OSError):
610 except (IOError, OSError):
562 if readonly:
611 if readonly:
563 # don't try to use cache - fall back to the slow path
612 # don't try to use cache - fall back to the slow path
564 self.branchinfo = self._branchinfo
613 self.branchinfo = self._branchinfo
565
614
566 if self._names:
615 if self._names:
567 try:
616 try:
568 data = repo.cachevfs.read(_rbcrevs)
617 data = repo.cachevfs.read(_rbcrevs)
569 self._rbcrevs[:] = data
618 self._rbcrevs[:] = data
570 except (IOError, OSError) as inst:
619 except (IOError, OSError) as inst:
571 repo.ui.debug(
620 repo.ui.debug(
572 b"couldn't read revision branch cache: %s\n"
621 b"couldn't read revision branch cache: %s\n"
573 % stringutil.forcebytestr(inst)
622 % stringutil.forcebytestr(inst)
574 )
623 )
575 # remember number of good records on disk
624 # remember number of good records on disk
576 self._rbcrevslen = min(
625 self._rbcrevslen = min(
577 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
626 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
578 )
627 )
579 if self._rbcrevslen == 0:
628 if self._rbcrevslen == 0:
580 self._names = []
629 self._names = []
581 self._rbcnamescount = len(self._names) # number of names read at
630 self._rbcnamescount = len(self._names) # number of names read at
582 # _rbcsnameslen
631 # _rbcsnameslen
583
632
584 def _clear(self):
633 def _clear(self):
585 self._rbcsnameslen = 0
634 self._rbcsnameslen = 0
586 del self._names[:]
635 del self._names[:]
587 self._rbcnamescount = 0
636 self._rbcnamescount = 0
588 self._rbcrevslen = len(self._repo.changelog)
637 self._rbcrevslen = len(self._repo.changelog)
589 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
638 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
590 util.clearcachedproperty(self, b'_namesreverse')
639 util.clearcachedproperty(self, b'_namesreverse')
591
640
592 @util.propertycache
641 @util.propertycache
593 def _namesreverse(self):
642 def _namesreverse(self):
594 return {b: r for r, b in enumerate(self._names)}
643 return {b: r for r, b in enumerate(self._names)}
595
644
596 def branchinfo(self, rev):
645 def branchinfo(self, rev):
597 """Return branch name and close flag for rev, using and updating
646 """Return branch name and close flag for rev, using and updating
598 persistent cache."""
647 persistent cache."""
599 changelog = self._repo.changelog
648 changelog = self._repo.changelog
600 rbcrevidx = rev * _rbcrecsize
649 rbcrevidx = rev * _rbcrecsize
601
650
602 # avoid negative index, changelog.read(nullrev) is fast without cache
651 # avoid negative index, changelog.read(nullrev) is fast without cache
603 if rev == nullrev:
652 if rev == nullrev:
604 return changelog.branchinfo(rev)
653 return changelog.branchinfo(rev)
605
654
606 # if requested rev isn't allocated, grow and cache the rev info
655 # if requested rev isn't allocated, grow and cache the rev info
607 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
656 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
608 return self._branchinfo(rev)
657 return self._branchinfo(rev)
609
658
610 # fast path: extract data from cache, use it if node is matching
659 # fast path: extract data from cache, use it if node is matching
611 reponode = changelog.node(rev)[:_rbcnodelen]
660 reponode = changelog.node(rev)[:_rbcnodelen]
612 cachenode, branchidx = unpack_from(
661 cachenode, branchidx = unpack_from(
613 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx
662 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx
614 )
663 )
615 close = bool(branchidx & _rbccloseflag)
664 close = bool(branchidx & _rbccloseflag)
616 if close:
665 if close:
617 branchidx &= _rbcbranchidxmask
666 branchidx &= _rbcbranchidxmask
618 if cachenode == b'\0\0\0\0':
667 if cachenode == b'\0\0\0\0':
619 pass
668 pass
620 elif cachenode == reponode:
669 elif cachenode == reponode:
621 try:
670 try:
622 return self._names[branchidx], close
671 return self._names[branchidx], close
623 except IndexError:
672 except IndexError:
624 # recover from invalid reference to unknown branch
673 # recover from invalid reference to unknown branch
625 self._repo.ui.debug(
674 self._repo.ui.debug(
626 b"referenced branch names not found"
675 b"referenced branch names not found"
627 b" - rebuilding revision branch cache from scratch\n"
676 b" - rebuilding revision branch cache from scratch\n"
628 )
677 )
629 self._clear()
678 self._clear()
630 else:
679 else:
631 # rev/node map has changed, invalidate the cache from here up
680 # rev/node map has changed, invalidate the cache from here up
632 self._repo.ui.debug(
681 self._repo.ui.debug(
633 b"history modification detected - truncating "
682 b"history modification detected - truncating "
634 b"revision branch cache to revision %d\n" % rev
683 b"revision branch cache to revision %d\n" % rev
635 )
684 )
636 truncate = rbcrevidx + _rbcrecsize
685 truncate = rbcrevidx + _rbcrecsize
637 del self._rbcrevs[truncate:]
686 del self._rbcrevs[truncate:]
638 self._rbcrevslen = min(self._rbcrevslen, truncate)
687 self._rbcrevslen = min(self._rbcrevslen, truncate)
639
688
640 # fall back to slow path and make sure it will be written to disk
689 # fall back to slow path and make sure it will be written to disk
641 return self._branchinfo(rev)
690 return self._branchinfo(rev)
642
691
643 def _branchinfo(self, rev):
692 def _branchinfo(self, rev):
644 """Retrieve branch info from changelog and update _rbcrevs"""
693 """Retrieve branch info from changelog and update _rbcrevs"""
645 changelog = self._repo.changelog
694 changelog = self._repo.changelog
646 b, close = changelog.branchinfo(rev)
695 b, close = changelog.branchinfo(rev)
647 if b in self._namesreverse:
696 if b in self._namesreverse:
648 branchidx = self._namesreverse[b]
697 branchidx = self._namesreverse[b]
649 else:
698 else:
650 branchidx = len(self._names)
699 branchidx = len(self._names)
651 self._names.append(b)
700 self._names.append(b)
652 self._namesreverse[b] = branchidx
701 self._namesreverse[b] = branchidx
653 reponode = changelog.node(rev)
702 reponode = changelog.node(rev)
654 if close:
703 if close:
655 branchidx |= _rbccloseflag
704 branchidx |= _rbccloseflag
656 self._setcachedata(rev, reponode, branchidx)
705 self._setcachedata(rev, reponode, branchidx)
657 return b, close
706 return b, close
658
707
659 def setdata(self, branch, rev, node, close):
708 def setdata(self, branch, rev, node, close):
660 """add new data information to the cache"""
709 """add new data information to the cache"""
661 if branch in self._namesreverse:
710 if branch in self._namesreverse:
662 branchidx = self._namesreverse[branch]
711 branchidx = self._namesreverse[branch]
663 else:
712 else:
664 branchidx = len(self._names)
713 branchidx = len(self._names)
665 self._names.append(branch)
714 self._names.append(branch)
666 self._namesreverse[branch] = branchidx
715 self._namesreverse[branch] = branchidx
667 if close:
716 if close:
668 branchidx |= _rbccloseflag
717 branchidx |= _rbccloseflag
669 self._setcachedata(rev, node, branchidx)
718 self._setcachedata(rev, node, branchidx)
670 # If no cache data were readable (non exists, bad permission, etc)
719 # If no cache data were readable (non exists, bad permission, etc)
671 # the cache was bypassing itself by setting:
720 # the cache was bypassing itself by setting:
672 #
721 #
673 # self.branchinfo = self._branchinfo
722 # self.branchinfo = self._branchinfo
674 #
723 #
675 # Since we now have data in the cache, we need to drop this bypassing.
724 # Since we now have data in the cache, we need to drop this bypassing.
676 if 'branchinfo' in vars(self):
725 if 'branchinfo' in vars(self):
677 del self.branchinfo
726 del self.branchinfo
678
727
679 def _setcachedata(self, rev, node, branchidx):
728 def _setcachedata(self, rev, node, branchidx):
680 """Writes the node's branch data to the in-memory cache data."""
729 """Writes the node's branch data to the in-memory cache data."""
681 if rev == nullrev:
730 if rev == nullrev:
682 return
731 return
683 rbcrevidx = rev * _rbcrecsize
732 rbcrevidx = rev * _rbcrecsize
684 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
733 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
685 self._rbcrevs.extend(
734 self._rbcrevs.extend(
686 b'\0'
735 b'\0'
687 * (len(self._repo.changelog) * _rbcrecsize - len(self._rbcrevs))
736 * (len(self._repo.changelog) * _rbcrecsize - len(self._rbcrevs))
688 )
737 )
689 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
738 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
690 self._rbcrevslen = min(self._rbcrevslen, rev)
739 self._rbcrevslen = min(self._rbcrevslen, rev)
691
740
692 tr = self._repo.currenttransaction()
741 tr = self._repo.currenttransaction()
693 if tr:
742 if tr:
694 tr.addfinalize(b'write-revbranchcache', self.write)
743 tr.addfinalize(b'write-revbranchcache', self.write)
695
744
696 def write(self, tr=None):
745 def write(self, tr=None):
697 """Save branch cache if it is dirty."""
746 """Save branch cache if it is dirty."""
698 repo = self._repo
747 repo = self._repo
699 wlock = None
748 wlock = None
700 step = b''
749 step = b''
701 try:
750 try:
702 # write the new names
751 # write the new names
703 if self._rbcnamescount < len(self._names):
752 if self._rbcnamescount < len(self._names):
704 wlock = repo.wlock(wait=False)
753 wlock = repo.wlock(wait=False)
705 step = b' names'
754 step = b' names'
706 self._writenames(repo)
755 self._writenames(repo)
707
756
708 # write the new revs
757 # write the new revs
709 start = self._rbcrevslen * _rbcrecsize
758 start = self._rbcrevslen * _rbcrecsize
710 if start != len(self._rbcrevs):
759 if start != len(self._rbcrevs):
711 step = b''
760 step = b''
712 if wlock is None:
761 if wlock is None:
713 wlock = repo.wlock(wait=False)
762 wlock = repo.wlock(wait=False)
714 self._writerevs(repo, start)
763 self._writerevs(repo, start)
715
764
716 except (IOError, OSError, error.Abort, error.LockError) as inst:
765 except (IOError, OSError, error.Abort, error.LockError) as inst:
717 repo.ui.debug(
766 repo.ui.debug(
718 b"couldn't write revision branch cache%s: %s\n"
767 b"couldn't write revision branch cache%s: %s\n"
719 % (step, stringutil.forcebytestr(inst))
768 % (step, stringutil.forcebytestr(inst))
720 )
769 )
721 finally:
770 finally:
722 if wlock is not None:
771 if wlock is not None:
723 wlock.release()
772 wlock.release()
724
773
725 def _writenames(self, repo):
774 def _writenames(self, repo):
726 """ write the new branch names to revbranchcache """
775 """ write the new branch names to revbranchcache """
727 if self._rbcnamescount != 0:
776 if self._rbcnamescount != 0:
728 f = repo.cachevfs.open(_rbcnames, b'ab')
777 f = repo.cachevfs.open(_rbcnames, b'ab')
729 if f.tell() == self._rbcsnameslen:
778 if f.tell() == self._rbcsnameslen:
730 f.write(b'\0')
779 f.write(b'\0')
731 else:
780 else:
732 f.close()
781 f.close()
733 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames)
782 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames)
734 self._rbcnamescount = 0
783 self._rbcnamescount = 0
735 self._rbcrevslen = 0
784 self._rbcrevslen = 0
736 if self._rbcnamescount == 0:
785 if self._rbcnamescount == 0:
737 # before rewriting names, make sure references are removed
786 # before rewriting names, make sure references are removed
738 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
787 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
739 f = repo.cachevfs.open(_rbcnames, b'wb')
788 f = repo.cachevfs.open(_rbcnames, b'wb')
740 f.write(
789 f.write(
741 b'\0'.join(
790 b'\0'.join(
742 encoding.fromlocal(b)
791 encoding.fromlocal(b)
743 for b in self._names[self._rbcnamescount :]
792 for b in self._names[self._rbcnamescount :]
744 )
793 )
745 )
794 )
746 self._rbcsnameslen = f.tell()
795 self._rbcsnameslen = f.tell()
747 f.close()
796 f.close()
748 self._rbcnamescount = len(self._names)
797 self._rbcnamescount = len(self._names)
749
798
750 def _writerevs(self, repo, start):
799 def _writerevs(self, repo, start):
751 """ write the new revs to revbranchcache """
800 """ write the new revs to revbranchcache """
752 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
801 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
753 with repo.cachevfs.open(_rbcrevs, b'ab') as f:
802 with repo.cachevfs.open(_rbcrevs, b'ab') as f:
754 if f.tell() != start:
803 if f.tell() != start:
755 repo.ui.debug(
804 repo.ui.debug(
756 b"truncating cache/%s to %d\n" % (_rbcrevs, start)
805 b"truncating cache/%s to %d\n" % (_rbcrevs, start)
757 )
806 )
758 f.seek(start)
807 f.seek(start)
759 if f.tell() != start:
808 if f.tell() != start:
760 start = 0
809 start = 0
761 f.seek(start)
810 f.seek(start)
762 f.truncate()
811 f.truncate()
763 end = revs * _rbcrecsize
812 end = revs * _rbcrecsize
764 f.write(self._rbcrevs[start:end])
813 f.write(self._rbcrevs[start:end])
765 self._rbcrevslen = revs
814 self._rbcrevslen = revs
@@ -1,62 +1,66 b''
1 == New Features ==
1 == New Features ==
2
2
3 * There is a new config section for templates used by hg commands. It
3 * There is a new config section for templates used by hg commands. It
4 is called `[command-templates]`. Some existing config options have
4 is called `[command-templates]`. Some existing config options have
5 been deprecated in favor of config options in the new
5 been deprecated in favor of config options in the new
6 section. These are: `ui.logtemplate` to `command-templates.log`,
6 section. These are: `ui.logtemplate` to `command-templates.log`,
7 `ui.graphnodetemplate` to `command-templates.graphnode`,
7 `ui.graphnodetemplate` to `command-templates.graphnode`,
8 `ui.mergemarkertemplate` to `command-templates.mergemarker`,
8 `ui.mergemarkertemplate` to `command-templates.mergemarker`,
9 `ui.pre-merge-tool-output-template` to
9 `ui.pre-merge-tool-output-template` to
10 `command-templates.pre-merge-tool-output`.
10 `command-templates.pre-merge-tool-output`.
11
11
12 * There is a new set of config options for the template used for the
12 * There is a new set of config options for the template used for the
13 one-line commit summary displayed by various commands, such as `hg
13 one-line commit summary displayed by various commands, such as `hg
14 rebase`. The main one is `command-templates.oneline-summary`. That
14 rebase`. The main one is `command-templates.oneline-summary`. That
15 can be overridden per command with
15 can be overridden per command with
16 `command-templates.oneline-summary.<command>`, where `<command>`
16 `command-templates.oneline-summary.<command>`, where `<command>`
17 can be e.g. `rebase`. As part of this effort, the default format
17 can be e.g. `rebase`. As part of this effort, the default format
18 from `hg rebase` was reorganized a bit.
18 from `hg rebase` was reorganized a bit.
19
19
20 * `hg strip`, from the strip extension, is now a core command, `hg
20 * `hg strip`, from the strip extension, is now a core command, `hg
21 debugstrip`. The extension remains for compatibility.
21 debugstrip`. The extension remains for compatibility.
22
22
23 * `hg diff` and `hg extdiff` now support `--from <rev>` and `--to <rev>`
23 * `hg diff` and `hg extdiff` now support `--from <rev>` and `--to <rev>`
24 arguments as clearer alternatives to `-r <revs>`. `-r <revs>` has been
24 arguments as clearer alternatives to `-r <revs>`. `-r <revs>` has been
25 deprecated.
25 deprecated.
26
26
27 * The memory footprint per changeset during pull/unbundle
27 * The memory footprint per changeset during pull/unbundle
28 operations has been further reduced.
28 operations has been further reduced.
29
29
30 * There is a new internal merge tool called `internal:mergediff` (can
30 * There is a new internal merge tool called `internal:mergediff` (can
31 be set as the value for the `merge` config in the `[ui]`
31 be set as the value for the `merge` config in the `[ui]`
32 section). It resolves merges the same was as `internal:merge` and
32 section). It resolves merges the same was as `internal:merge` and
33 `internal:merge3`, but it shows conflicts differently. Instead of
33 `internal:merge3`, but it shows conflicts differently. Instead of
34 showing 2 or 3 snapshots of the conflicting pieces of code, it
34 showing 2 or 3 snapshots of the conflicting pieces of code, it
35 shows one snapshot and a diff. This may be useful when at least one
35 shows one snapshot and a diff. This may be useful when at least one
36 side of the conflict is similar to the base. The new marker style
36 side of the conflict is similar to the base. The new marker style
37 is also supported by "premerge" as
37 is also supported by "premerge" as
38 `merge-tools.<tool>.premerge=keep-mergediff`.
38 `merge-tools.<tool>.premerge=keep-mergediff`.
39
39
40 * External hooks are now called with `HGPLAIN=1` preset.
40 * External hooks are now called with `HGPLAIN=1` preset.
41
41
42 * The `branchmap` cache is updated more intelligently and can be
43 significantly faster for repositories with many branches and changesets.
44
45
42 == New Experimental Features ==
46 == New Experimental Features ==
43
47
44 * `experimental.single-head-per-branch:public-changes-only` can be used
48 * `experimental.single-head-per-branch:public-changes-only` can be used
45 restrict the single head check to public revision. This is useful for
49 restrict the single head check to public revision. This is useful for
46 overlay repository that have both a publishing and non-publishing view
50 overlay repository that have both a publishing and non-publishing view
47 of the same storage.
51 of the same storage.
48
52
49
53
50 == Bug Fixes ==
54 == Bug Fixes ==
51
55
52
56
53
57
54 == Backwards Compatibility Changes ==
58 == Backwards Compatibility Changes ==
55
59
56 * `--force-lock` and `--force-wlock` options on `hg debuglock` command are
60 * `--force-lock` and `--force-wlock` options on `hg debuglock` command are
57 renamed to `--force-free-lock` and `--force-free-wlock` respectively.
61 renamed to `--force-free-lock` and `--force-free-wlock` respectively.
58
62
59
63
60 == Internal API Changes ==
64 == Internal API Changes ==
61
65
62
66
@@ -1,990 +1,1244 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
6
7 Basic test
7 Basic test
8 $ echo 'root' >root
8 $ echo 'root' >root
9 $ hg add root
9 $ hg add root
10 $ hg commit -d '0 0' -m "Adding root node"
10 $ hg commit -d '0 0' -m "Adding root node"
11
11
12 $ echo 'a' >a
12 $ echo 'a' >a
13 $ hg add a
13 $ hg add a
14 $ hg branch a
14 $ hg branch a
15 marked working directory as branch a
15 marked working directory as branch a
16 (branches are permanent and global, did you want a bookmark?)
16 (branches are permanent and global, did you want a bookmark?)
17 $ hg commit -d '1 0' -m "Adding a branch"
17 $ hg commit -d '1 0' -m "Adding a branch"
18
18
19 $ hg branch q
19 $ hg branch q
20 marked working directory as branch q
20 marked working directory as branch q
21 $ echo 'aa' >a
21 $ echo 'aa' >a
22 $ hg branch -C
22 $ hg branch -C
23 reset working directory to branch a
23 reset working directory to branch a
24 $ hg commit -d '2 0' -m "Adding to a branch"
24 $ hg commit -d '2 0' -m "Adding to a branch"
25
25
26 $ hg update -C 0
26 $ hg update -C 0
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 $ echo 'b' >b
28 $ echo 'b' >b
29 $ hg add b
29 $ hg add b
30 $ hg branch b
30 $ hg branch b
31 marked working directory as branch b
31 marked working directory as branch b
32 $ hg commit -d '2 0' -m "Adding b branch"
32 $ hg commit -d '2 0' -m "Adding b branch"
33
33
34 $ echo 'bh1' >bh1
34 $ echo 'bh1' >bh1
35 $ hg add bh1
35 $ hg add bh1
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
37
37
38 $ hg update -C 2
38 $ hg update -C 2
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
40 $ echo 'bh2' >bh2
40 $ echo 'bh2' >bh2
41 $ hg add bh2
41 $ hg add bh2
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
43
43
44 $ echo 'c' >c
44 $ echo 'c' >c
45 $ hg add c
45 $ hg add c
46 $ hg branch c
46 $ hg branch c
47 marked working directory as branch c
47 marked working directory as branch c
48 $ hg commit -d '5 0' -m "Adding c branch"
48 $ hg commit -d '5 0' -m "Adding c branch"
49
49
50 reserved names
50 reserved names
51
51
52 $ hg branch tip
52 $ hg branch tip
53 abort: the name 'tip' is reserved
53 abort: the name 'tip' is reserved
54 [10]
54 [10]
55 $ hg branch null
55 $ hg branch null
56 abort: the name 'null' is reserved
56 abort: the name 'null' is reserved
57 [10]
57 [10]
58 $ hg branch .
58 $ hg branch .
59 abort: the name '.' is reserved
59 abort: the name '.' is reserved
60 [10]
60 [10]
61
61
62 invalid characters
62 invalid characters
63
63
64 $ hg branch 'foo:bar'
64 $ hg branch 'foo:bar'
65 abort: ':' cannot be used in a name
65 abort: ':' cannot be used in a name
66 [10]
66 [10]
67
67
68 $ hg branch 'foo
68 $ hg branch 'foo
69 > bar'
69 > bar'
70 abort: '\n' cannot be used in a name
70 abort: '\n' cannot be used in a name
71 [10]
71 [10]
72
72
73 trailing or leading spaces should be stripped before testing duplicates
73 trailing or leading spaces should be stripped before testing duplicates
74
74
75 $ hg branch 'b '
75 $ hg branch 'b '
76 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
78 [10]
78 [10]
79
79
80 $ hg branch ' b'
80 $ hg branch ' b'
81 abort: a branch of the same name already exists
81 abort: a branch of the same name already exists
82 (use 'hg update' to switch to it)
82 (use 'hg update' to switch to it)
83 [10]
83 [10]
84
84
85 verify update will accept invalid legacy branch names
85 verify update will accept invalid legacy branch names
86
86
87 $ hg init test-invalid-branch-name
87 $ hg init test-invalid-branch-name
88 $ cd test-invalid-branch-name
88 $ cd test-invalid-branch-name
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 3 changesets with 3 changes to 2 files
93 added 3 changesets with 3 changes to 2 files
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96
96
97 $ hg update '"colon:test"'
97 $ hg update '"colon:test"'
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 $ cd ..
99 $ cd ..
100
100
101 $ echo 'd' >d
101 $ echo 'd' >d
102 $ hg add d
102 $ hg add d
103 $ hg branch 'a branch name much longer than the default justification used by branches'
103 $ hg branch 'a branch name much longer than the default justification used by branches'
104 marked working directory as branch a branch name much longer than the default justification used by branches
104 marked working directory as branch a branch name much longer than the default justification used by branches
105 $ hg commit -d '6 0' -m "Adding d branch"
105 $ hg commit -d '6 0' -m "Adding d branch"
106
106
107 $ hg branches
107 $ hg branches
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
109 b 4:aee39cd168d0
109 b 4:aee39cd168d0
110 c 6:589736a22561 (inactive)
110 c 6:589736a22561 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
112 default 0:19709c5a4e75 (inactive)
112 default 0:19709c5a4e75 (inactive)
113
113
114 -------
114 -------
115
115
116 $ hg branches -a
116 $ hg branches -a
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 b 4:aee39cd168d0
118 b 4:aee39cd168d0
119
119
120 --- Branch a
120 --- Branch a
121
121
122 $ hg log -b a
122 $ hg log -b a
123 changeset: 5:d8cbc61dbaa6
123 changeset: 5:d8cbc61dbaa6
124 branch: a
124 branch: a
125 parent: 2:881fe2b92ad0
125 parent: 2:881fe2b92ad0
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:04 1970 +0000
127 date: Thu Jan 01 00:00:04 1970 +0000
128 summary: Adding b branch head 2
128 summary: Adding b branch head 2
129
129
130 changeset: 2:881fe2b92ad0
130 changeset: 2:881fe2b92ad0
131 branch: a
131 branch: a
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:02 1970 +0000
133 date: Thu Jan 01 00:00:02 1970 +0000
134 summary: Adding to a branch
134 summary: Adding to a branch
135
135
136 changeset: 1:dd6b440dd85a
136 changeset: 1:dd6b440dd85a
137 branch: a
137 branch: a
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:01 1970 +0000
139 date: Thu Jan 01 00:00:01 1970 +0000
140 summary: Adding a branch
140 summary: Adding a branch
141
141
142
142
143 ---- Branch b
143 ---- Branch b
144
144
145 $ hg log -b b
145 $ hg log -b b
146 changeset: 4:aee39cd168d0
146 changeset: 4:aee39cd168d0
147 branch: b
147 branch: b
148 user: test
148 user: test
149 date: Thu Jan 01 00:00:03 1970 +0000
149 date: Thu Jan 01 00:00:03 1970 +0000
150 summary: Adding b branch head 1
150 summary: Adding b branch head 1
151
151
152 changeset: 3:ac22033332d1
152 changeset: 3:ac22033332d1
153 branch: b
153 branch: b
154 parent: 0:19709c5a4e75
154 parent: 0:19709c5a4e75
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:02 1970 +0000
156 date: Thu Jan 01 00:00:02 1970 +0000
157 summary: Adding b branch
157 summary: Adding b branch
158
158
159
159
160 ---- going to test branch listing by rev
160 ---- going to test branch listing by rev
161 $ hg branches -r0
161 $ hg branches -r0
162 default 0:19709c5a4e75 (inactive)
162 default 0:19709c5a4e75 (inactive)
163 $ hg branches -qr0
163 $ hg branches -qr0
164 default
164 default
165 --- now more than one rev
165 --- now more than one rev
166 $ hg branches -r2:5
166 $ hg branches -r2:5
167 b 4:aee39cd168d0
167 b 4:aee39cd168d0
168 a 5:d8cbc61dbaa6 (inactive)
168 a 5:d8cbc61dbaa6 (inactive)
169 $ hg branches -qr2:5
169 $ hg branches -qr2:5
170 b
170 b
171 a
171 a
172 ---- going to test branch closing
172 ---- going to test branch closing
173
173
174 $ hg branches
174 $ hg branches
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
176 b 4:aee39cd168d0
176 b 4:aee39cd168d0
177 c 6:589736a22561 (inactive)
177 c 6:589736a22561 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
179 default 0:19709c5a4e75 (inactive)
179 default 0:19709c5a4e75 (inactive)
180 $ hg up -C b
180 $ hg up -C b
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
182 $ echo 'xxx1' >> b
182 $ echo 'xxx1' >> b
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
184 $ hg up -C aee39cd168d0
184 $ hg up -C aee39cd168d0
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 $ echo 'xxx2' >> b
186 $ echo 'xxx2' >> b
187 $ hg commit -d '8 0' -m 'adding head to branch b'
187 $ hg commit -d '8 0' -m 'adding head to branch b'
188 created new head
188 created new head
189 $ echo 'xxx3' >> b
189 $ echo 'xxx3' >> b
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
191 $ hg branches
191 $ hg branches
192 b 10:bfbe841b666e
192 b 10:bfbe841b666e
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
194 c 6:589736a22561 (inactive)
194 c 6:589736a22561 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
196 default 0:19709c5a4e75 (inactive)
196 default 0:19709c5a4e75 (inactive)
197 $ hg heads --closed
197 $ hg heads --closed
198 changeset: 10:bfbe841b666e
198 changeset: 10:bfbe841b666e
199 branch: b
199 branch: b
200 tag: tip
200 tag: tip
201 user: test
201 user: test
202 date: Thu Jan 01 00:00:09 1970 +0000
202 date: Thu Jan 01 00:00:09 1970 +0000
203 summary: adding another cset to branch b
203 summary: adding another cset to branch b
204
204
205 changeset: 8:eebb944467c9
205 changeset: 8:eebb944467c9
206 branch: b
206 branch: b
207 parent: 4:aee39cd168d0
207 parent: 4:aee39cd168d0
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:07 1970 +0000
209 date: Thu Jan 01 00:00:07 1970 +0000
210 summary: adding cset to branch b
210 summary: adding cset to branch b
211
211
212 changeset: 7:10ff5895aa57
212 changeset: 7:10ff5895aa57
213 branch: a branch name much longer than the default justification used by branches
213 branch: a branch name much longer than the default justification used by branches
214 user: test
214 user: test
215 date: Thu Jan 01 00:00:06 1970 +0000
215 date: Thu Jan 01 00:00:06 1970 +0000
216 summary: Adding d branch
216 summary: Adding d branch
217
217
218 changeset: 6:589736a22561
218 changeset: 6:589736a22561
219 branch: c
219 branch: c
220 user: test
220 user: test
221 date: Thu Jan 01 00:00:05 1970 +0000
221 date: Thu Jan 01 00:00:05 1970 +0000
222 summary: Adding c branch
222 summary: Adding c branch
223
223
224 changeset: 5:d8cbc61dbaa6
224 changeset: 5:d8cbc61dbaa6
225 branch: a
225 branch: a
226 parent: 2:881fe2b92ad0
226 parent: 2:881fe2b92ad0
227 user: test
227 user: test
228 date: Thu Jan 01 00:00:04 1970 +0000
228 date: Thu Jan 01 00:00:04 1970 +0000
229 summary: Adding b branch head 2
229 summary: Adding b branch head 2
230
230
231 changeset: 0:19709c5a4e75
231 changeset: 0:19709c5a4e75
232 user: test
232 user: test
233 date: Thu Jan 01 00:00:00 1970 +0000
233 date: Thu Jan 01 00:00:00 1970 +0000
234 summary: Adding root node
234 summary: Adding root node
235
235
236 $ hg heads
236 $ hg heads
237 changeset: 10:bfbe841b666e
237 changeset: 10:bfbe841b666e
238 branch: b
238 branch: b
239 tag: tip
239 tag: tip
240 user: test
240 user: test
241 date: Thu Jan 01 00:00:09 1970 +0000
241 date: Thu Jan 01 00:00:09 1970 +0000
242 summary: adding another cset to branch b
242 summary: adding another cset to branch b
243
243
244 changeset: 8:eebb944467c9
244 changeset: 8:eebb944467c9
245 branch: b
245 branch: b
246 parent: 4:aee39cd168d0
246 parent: 4:aee39cd168d0
247 user: test
247 user: test
248 date: Thu Jan 01 00:00:07 1970 +0000
248 date: Thu Jan 01 00:00:07 1970 +0000
249 summary: adding cset to branch b
249 summary: adding cset to branch b
250
250
251 changeset: 7:10ff5895aa57
251 changeset: 7:10ff5895aa57
252 branch: a branch name much longer than the default justification used by branches
252 branch: a branch name much longer than the default justification used by branches
253 user: test
253 user: test
254 date: Thu Jan 01 00:00:06 1970 +0000
254 date: Thu Jan 01 00:00:06 1970 +0000
255 summary: Adding d branch
255 summary: Adding d branch
256
256
257 changeset: 6:589736a22561
257 changeset: 6:589736a22561
258 branch: c
258 branch: c
259 user: test
259 user: test
260 date: Thu Jan 01 00:00:05 1970 +0000
260 date: Thu Jan 01 00:00:05 1970 +0000
261 summary: Adding c branch
261 summary: Adding c branch
262
262
263 changeset: 5:d8cbc61dbaa6
263 changeset: 5:d8cbc61dbaa6
264 branch: a
264 branch: a
265 parent: 2:881fe2b92ad0
265 parent: 2:881fe2b92ad0
266 user: test
266 user: test
267 date: Thu Jan 01 00:00:04 1970 +0000
267 date: Thu Jan 01 00:00:04 1970 +0000
268 summary: Adding b branch head 2
268 summary: Adding b branch head 2
269
269
270 changeset: 0:19709c5a4e75
270 changeset: 0:19709c5a4e75
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:00 1970 +0000
272 date: Thu Jan 01 00:00:00 1970 +0000
273 summary: Adding root node
273 summary: Adding root node
274
274
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
276 $ hg branches -a
276 $ hg branches -a
277 b 8:eebb944467c9
277 b 8:eebb944467c9
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
279 $ hg up -C b
279 $ hg up -C b
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
283 abort: current revision is already a branch closing head
283 abort: current revision is already a branch closing head
284 [10]
284 [10]
285
285
286 $ hg log -r tip --debug
286 $ hg log -r tip --debug
287 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
287 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
288 branch: b
288 branch: b
289 tag: tip
289 tag: tip
290 phase: draft
290 phase: draft
291 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
291 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
292 parent: -1:0000000000000000000000000000000000000000
292 parent: -1:0000000000000000000000000000000000000000
293 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
293 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
294 user: test
294 user: test
295 date: Thu Jan 01 00:00:09 1970 +0000
295 date: Thu Jan 01 00:00:09 1970 +0000
296 extra: branch=b
296 extra: branch=b
297 extra: close=1
297 extra: close=1
298 description:
298 description:
299 close this part branch too
299 close this part branch too
300
300
301
301
302 --- b branch should be inactive
302 --- b branch should be inactive
303
303
304 $ hg branches
304 $ hg branches
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 c 6:589736a22561 (inactive)
306 c 6:589736a22561 (inactive)
307 a 5:d8cbc61dbaa6 (inactive)
307 a 5:d8cbc61dbaa6 (inactive)
308 default 0:19709c5a4e75 (inactive)
308 default 0:19709c5a4e75 (inactive)
309 $ hg branches -c
309 $ hg branches -c
310 a branch name much longer than the default justification used by branches 7:10ff5895aa57
310 a branch name much longer than the default justification used by branches 7:10ff5895aa57
311 b 12:e3d49c0575d8 (closed)
311 b 12:e3d49c0575d8 (closed)
312 c 6:589736a22561 (inactive)
312 c 6:589736a22561 (inactive)
313 a 5:d8cbc61dbaa6 (inactive)
313 a 5:d8cbc61dbaa6 (inactive)
314 default 0:19709c5a4e75 (inactive)
314 default 0:19709c5a4e75 (inactive)
315 $ hg branches -a
315 $ hg branches -a
316 a branch name much longer than the default justification used by branches 7:10ff5895aa57
316 a branch name much longer than the default justification used by branches 7:10ff5895aa57
317 $ hg branches -q
317 $ hg branches -q
318 a branch name much longer than the default justification used by branches
318 a branch name much longer than the default justification used by branches
319 c
319 c
320 a
320 a
321 default
321 default
322 $ hg heads b
322 $ hg heads b
323 no open branch heads found on branches b
323 no open branch heads found on branches b
324 [1]
324 [1]
325 $ hg heads --closed b
325 $ hg heads --closed b
326 changeset: 12:e3d49c0575d8
326 changeset: 12:e3d49c0575d8
327 branch: b
327 branch: b
328 tag: tip
328 tag: tip
329 parent: 8:eebb944467c9
329 parent: 8:eebb944467c9
330 user: test
330 user: test
331 date: Thu Jan 01 00:00:09 1970 +0000
331 date: Thu Jan 01 00:00:09 1970 +0000
332 summary: close this part branch too
332 summary: close this part branch too
333
333
334 changeset: 11:d3f163457ebf
334 changeset: 11:d3f163457ebf
335 branch: b
335 branch: b
336 user: test
336 user: test
337 date: Thu Jan 01 00:00:09 1970 +0000
337 date: Thu Jan 01 00:00:09 1970 +0000
338 summary: prune bad branch
338 summary: prune bad branch
339
339
340 $ echo 'xxx4' >> b
340 $ echo 'xxx4' >> b
341 $ hg commit -d '9 0' -m 'reopen branch with a change'
341 $ hg commit -d '9 0' -m 'reopen branch with a change'
342 reopening closed branch head 12
342 reopening closed branch head 12
343
343
344 --- branch b is back in action
344 --- branch b is back in action
345
345
346 $ hg branches -a
346 $ hg branches -a
347 b 13:e23b5505d1ad
347 b 13:e23b5505d1ad
348 a branch name much longer than the default justification used by branches 7:10ff5895aa57
348 a branch name much longer than the default justification used by branches 7:10ff5895aa57
349
349
350 ---- test heads listings
350 ---- test heads listings
351
351
352 $ hg heads
352 $ hg heads
353 changeset: 13:e23b5505d1ad
353 changeset: 13:e23b5505d1ad
354 branch: b
354 branch: b
355 tag: tip
355 tag: tip
356 user: test
356 user: test
357 date: Thu Jan 01 00:00:09 1970 +0000
357 date: Thu Jan 01 00:00:09 1970 +0000
358 summary: reopen branch with a change
358 summary: reopen branch with a change
359
359
360 changeset: 7:10ff5895aa57
360 changeset: 7:10ff5895aa57
361 branch: a branch name much longer than the default justification used by branches
361 branch: a branch name much longer than the default justification used by branches
362 user: test
362 user: test
363 date: Thu Jan 01 00:00:06 1970 +0000
363 date: Thu Jan 01 00:00:06 1970 +0000
364 summary: Adding d branch
364 summary: Adding d branch
365
365
366 changeset: 6:589736a22561
366 changeset: 6:589736a22561
367 branch: c
367 branch: c
368 user: test
368 user: test
369 date: Thu Jan 01 00:00:05 1970 +0000
369 date: Thu Jan 01 00:00:05 1970 +0000
370 summary: Adding c branch
370 summary: Adding c branch
371
371
372 changeset: 5:d8cbc61dbaa6
372 changeset: 5:d8cbc61dbaa6
373 branch: a
373 branch: a
374 parent: 2:881fe2b92ad0
374 parent: 2:881fe2b92ad0
375 user: test
375 user: test
376 date: Thu Jan 01 00:00:04 1970 +0000
376 date: Thu Jan 01 00:00:04 1970 +0000
377 summary: Adding b branch head 2
377 summary: Adding b branch head 2
378
378
379 changeset: 0:19709c5a4e75
379 changeset: 0:19709c5a4e75
380 user: test
380 user: test
381 date: Thu Jan 01 00:00:00 1970 +0000
381 date: Thu Jan 01 00:00:00 1970 +0000
382 summary: Adding root node
382 summary: Adding root node
383
383
384
384
385 branch default
385 branch default
386
386
387 $ hg heads default
387 $ hg heads default
388 changeset: 0:19709c5a4e75
388 changeset: 0:19709c5a4e75
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:00 1970 +0000
390 date: Thu Jan 01 00:00:00 1970 +0000
391 summary: Adding root node
391 summary: Adding root node
392
392
393
393
394 branch a
394 branch a
395
395
396 $ hg heads a
396 $ hg heads a
397 changeset: 5:d8cbc61dbaa6
397 changeset: 5:d8cbc61dbaa6
398 branch: a
398 branch: a
399 parent: 2:881fe2b92ad0
399 parent: 2:881fe2b92ad0
400 user: test
400 user: test
401 date: Thu Jan 01 00:00:04 1970 +0000
401 date: Thu Jan 01 00:00:04 1970 +0000
402 summary: Adding b branch head 2
402 summary: Adding b branch head 2
403
403
404 $ hg heads --active a
404 $ hg heads --active a
405 no open branch heads found on branches a
405 no open branch heads found on branches a
406 [1]
406 [1]
407
407
408 branch b
408 branch b
409
409
410 $ hg heads b
410 $ hg heads b
411 changeset: 13:e23b5505d1ad
411 changeset: 13:e23b5505d1ad
412 branch: b
412 branch: b
413 tag: tip
413 tag: tip
414 user: test
414 user: test
415 date: Thu Jan 01 00:00:09 1970 +0000
415 date: Thu Jan 01 00:00:09 1970 +0000
416 summary: reopen branch with a change
416 summary: reopen branch with a change
417
417
418 $ hg heads --closed b
418 $ hg heads --closed b
419 changeset: 13:e23b5505d1ad
419 changeset: 13:e23b5505d1ad
420 branch: b
420 branch: b
421 tag: tip
421 tag: tip
422 user: test
422 user: test
423 date: Thu Jan 01 00:00:09 1970 +0000
423 date: Thu Jan 01 00:00:09 1970 +0000
424 summary: reopen branch with a change
424 summary: reopen branch with a change
425
425
426 changeset: 11:d3f163457ebf
426 changeset: 11:d3f163457ebf
427 branch: b
427 branch: b
428 user: test
428 user: test
429 date: Thu Jan 01 00:00:09 1970 +0000
429 date: Thu Jan 01 00:00:09 1970 +0000
430 summary: prune bad branch
430 summary: prune bad branch
431
431
432
432
433 reclose branch
433 reclose branch
434
434
435 $ hg up -C c
435 $ hg up -C c
436 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
436 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
437 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
437 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
438 $ hg branches
438 $ hg branches
439 b 13:e23b5505d1ad
439 b 13:e23b5505d1ad
440 a branch name much longer than the default justification used by branches 7:10ff5895aa57
440 a branch name much longer than the default justification used by branches 7:10ff5895aa57
441 a 5:d8cbc61dbaa6 (inactive)
441 a 5:d8cbc61dbaa6 (inactive)
442 default 0:19709c5a4e75 (inactive)
442 default 0:19709c5a4e75 (inactive)
443 $ hg branches --closed
443 $ hg branches --closed
444 b 13:e23b5505d1ad
444 b 13:e23b5505d1ad
445 a branch name much longer than the default justification used by branches 7:10ff5895aa57
445 a branch name much longer than the default justification used by branches 7:10ff5895aa57
446 c 14:f894c25619d3 (closed)
446 c 14:f894c25619d3 (closed)
447 a 5:d8cbc61dbaa6 (inactive)
447 a 5:d8cbc61dbaa6 (inactive)
448 default 0:19709c5a4e75 (inactive)
448 default 0:19709c5a4e75 (inactive)
449
449
450 multihead branch
450 multihead branch
451
451
452 $ hg up -C default
452 $ hg up -C default
453 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
453 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
454 $ hg branch m
454 $ hg branch m
455 marked working directory as branch m
455 marked working directory as branch m
456 $ touch m
456 $ touch m
457 $ hg add m
457 $ hg add m
458 $ hg commit -d '10 0' -m 'multihead base'
458 $ hg commit -d '10 0' -m 'multihead base'
459 $ echo "m1" >m
459 $ echo "m1" >m
460 $ hg commit -d '10 0' -m 'head 1'
460 $ hg commit -d '10 0' -m 'head 1'
461 $ hg up -C '.^'
461 $ hg up -C '.^'
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ echo "m2" >m
463 $ echo "m2" >m
464 $ hg commit -d '10 0' -m 'head 2'
464 $ hg commit -d '10 0' -m 'head 2'
465 created new head
465 created new head
466 $ hg log -b m
466 $ hg log -b m
467 changeset: 17:df343b0df04f
467 changeset: 17:df343b0df04f
468 branch: m
468 branch: m
469 tag: tip
469 tag: tip
470 parent: 15:f3447637f53e
470 parent: 15:f3447637f53e
471 user: test
471 user: test
472 date: Thu Jan 01 00:00:10 1970 +0000
472 date: Thu Jan 01 00:00:10 1970 +0000
473 summary: head 2
473 summary: head 2
474
474
475 changeset: 16:a58ca5d3bdf3
475 changeset: 16:a58ca5d3bdf3
476 branch: m
476 branch: m
477 user: test
477 user: test
478 date: Thu Jan 01 00:00:10 1970 +0000
478 date: Thu Jan 01 00:00:10 1970 +0000
479 summary: head 1
479 summary: head 1
480
480
481 changeset: 15:f3447637f53e
481 changeset: 15:f3447637f53e
482 branch: m
482 branch: m
483 parent: 0:19709c5a4e75
483 parent: 0:19709c5a4e75
484 user: test
484 user: test
485 date: Thu Jan 01 00:00:10 1970 +0000
485 date: Thu Jan 01 00:00:10 1970 +0000
486 summary: multihead base
486 summary: multihead base
487
487
488 $ hg heads --topo m
488 $ hg heads --topo m
489 changeset: 17:df343b0df04f
489 changeset: 17:df343b0df04f
490 branch: m
490 branch: m
491 tag: tip
491 tag: tip
492 parent: 15:f3447637f53e
492 parent: 15:f3447637f53e
493 user: test
493 user: test
494 date: Thu Jan 01 00:00:10 1970 +0000
494 date: Thu Jan 01 00:00:10 1970 +0000
495 summary: head 2
495 summary: head 2
496
496
497 changeset: 16:a58ca5d3bdf3
497 changeset: 16:a58ca5d3bdf3
498 branch: m
498 branch: m
499 user: test
499 user: test
500 date: Thu Jan 01 00:00:10 1970 +0000
500 date: Thu Jan 01 00:00:10 1970 +0000
501 summary: head 1
501 summary: head 1
502
502
503 $ hg branches
503 $ hg branches
504 m 17:df343b0df04f
504 m 17:df343b0df04f
505 b 13:e23b5505d1ad
505 b 13:e23b5505d1ad
506 a branch name much longer than the default justification used by branches 7:10ff5895aa57
506 a branch name much longer than the default justification used by branches 7:10ff5895aa57
507 a 5:d8cbc61dbaa6 (inactive)
507 a 5:d8cbc61dbaa6 (inactive)
508 default 0:19709c5a4e75 (inactive)
508 default 0:19709c5a4e75 (inactive)
509
509
510 partially merge multihead branch
510 partially merge multihead branch
511
511
512 $ hg up -C default
512 $ hg up -C default
513 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
513 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
514 $ hg branch md
514 $ hg branch md
515 marked working directory as branch md
515 marked working directory as branch md
516 $ hg merge m
516 $ hg merge m
517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 (branch merge, don't forget to commit)
518 (branch merge, don't forget to commit)
519 $ hg commit -d '11 0' -m 'merge head 2'
519 $ hg commit -d '11 0' -m 'merge head 2'
520 $ hg heads --topo m
520 $ hg heads --topo m
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 $ hg branches
527 $ hg branches
528 md 18:c914c99f1fbb
528 md 18:c914c99f1fbb
529 m 17:df343b0df04f
529 m 17:df343b0df04f
530 b 13:e23b5505d1ad
530 b 13:e23b5505d1ad
531 a branch name much longer than the default justification used by branches 7:10ff5895aa57
531 a branch name much longer than the default justification used by branches 7:10ff5895aa57
532 a 5:d8cbc61dbaa6 (inactive)
532 a 5:d8cbc61dbaa6 (inactive)
533 default 0:19709c5a4e75 (inactive)
533 default 0:19709c5a4e75 (inactive)
534
534
535 partially close multihead branch
535 partially close multihead branch
536
536
537 $ hg up -C a58ca5d3bdf3
537 $ hg up -C a58ca5d3bdf3
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 $ hg commit -d '12 0' -m 'close head 1' --close-branch
539 $ hg commit -d '12 0' -m 'close head 1' --close-branch
540 $ hg heads --topo m
540 $ hg heads --topo m
541 changeset: 19:cd21a80baa3d
541 changeset: 19:cd21a80baa3d
542 branch: m
542 branch: m
543 tag: tip
543 tag: tip
544 parent: 16:a58ca5d3bdf3
544 parent: 16:a58ca5d3bdf3
545 user: test
545 user: test
546 date: Thu Jan 01 00:00:12 1970 +0000
546 date: Thu Jan 01 00:00:12 1970 +0000
547 summary: close head 1
547 summary: close head 1
548
548
549 $ hg branches
549 $ hg branches
550 md 18:c914c99f1fbb
550 md 18:c914c99f1fbb
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 m 17:df343b0df04f (inactive)
553 m 17:df343b0df04f (inactive)
554 a 5:d8cbc61dbaa6 (inactive)
554 a 5:d8cbc61dbaa6 (inactive)
555 default 0:19709c5a4e75 (inactive)
555 default 0:19709c5a4e75 (inactive)
556
556
557 default branch colors:
557 default branch colors:
558
558
559 $ cat <<EOF >> $HGRCPATH
559 $ cat <<EOF >> $HGRCPATH
560 > [extensions]
560 > [extensions]
561 > color =
561 > color =
562 > [color]
562 > [color]
563 > mode = ansi
563 > mode = ansi
564 > EOF
564 > EOF
565
565
566 $ hg up -C b
566 $ hg up -C b
567 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
567 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
568 $ hg branches --color=always
568 $ hg branches --color=always
569 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
569 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
570 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
570 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
571 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
571 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
572 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
572 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
575
575
576 default closed branch color:
576 default closed branch color:
577
577
578 $ hg branches --color=always --closed
578 $ hg branches --color=always --closed
579 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
579 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
580 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
580 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
581 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
581 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
582 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
582 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
583 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
583 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
584 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
584 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
585 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
585 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
586
586
587 $ cat <<EOF >> $HGRCPATH
587 $ cat <<EOF >> $HGRCPATH
588 > [extensions]
588 > [extensions]
589 > color =
589 > color =
590 > [color]
590 > [color]
591 > branches.active = green
591 > branches.active = green
592 > branches.closed = blue
592 > branches.closed = blue
593 > branches.current = red
593 > branches.current = red
594 > branches.inactive = magenta
594 > branches.inactive = magenta
595 > log.changeset = cyan
595 > log.changeset = cyan
596 > EOF
596 > EOF
597
597
598 custom branch colors:
598 custom branch colors:
599
599
600 $ hg branches --color=always
600 $ hg branches --color=always
601 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
601 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
602 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
602 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
603 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
603 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
604 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
604 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
607
607
608 custom closed branch color:
608 custom closed branch color:
609
609
610 $ hg branches --color=always --closed
610 $ hg branches --color=always --closed
611 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
611 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
612 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
612 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
613 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
613 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
614 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
614 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
615 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
615 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
616 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
616 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
617 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
617 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
618
618
619 template output:
619 template output:
620
620
621 $ hg branches -Tjson --closed
621 $ hg branches -Tjson --closed
622 [
622 [
623 {
623 {
624 "active": true,
624 "active": true,
625 "branch": "md",
625 "branch": "md",
626 "closed": false,
626 "closed": false,
627 "current": false,
627 "current": false,
628 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
628 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
629 "rev": 18
629 "rev": 18
630 },
630 },
631 {
631 {
632 "active": true,
632 "active": true,
633 "branch": "b",
633 "branch": "b",
634 "closed": false,
634 "closed": false,
635 "current": true,
635 "current": true,
636 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
636 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
637 "rev": 13
637 "rev": 13
638 },
638 },
639 {
639 {
640 "active": true,
640 "active": true,
641 "branch": "a branch name much longer than the default justification used by branches",
641 "branch": "a branch name much longer than the default justification used by branches",
642 "closed": false,
642 "closed": false,
643 "current": false,
643 "current": false,
644 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
644 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
645 "rev": 7
645 "rev": 7
646 },
646 },
647 {
647 {
648 "active": false,
648 "active": false,
649 "branch": "m",
649 "branch": "m",
650 "closed": false,
650 "closed": false,
651 "current": false,
651 "current": false,
652 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
652 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
653 "rev": 17
653 "rev": 17
654 },
654 },
655 {
655 {
656 "active": false,
656 "active": false,
657 "branch": "c",
657 "branch": "c",
658 "closed": true,
658 "closed": true,
659 "current": false,
659 "current": false,
660 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
660 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
661 "rev": 14
661 "rev": 14
662 },
662 },
663 {
663 {
664 "active": false,
664 "active": false,
665 "branch": "a",
665 "branch": "a",
666 "closed": false,
666 "closed": false,
667 "current": false,
667 "current": false,
668 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
668 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
669 "rev": 5
669 "rev": 5
670 },
670 },
671 {
671 {
672 "active": false,
672 "active": false,
673 "branch": "default",
673 "branch": "default",
674 "closed": false,
674 "closed": false,
675 "current": false,
675 "current": false,
676 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
676 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
677 "rev": 0
677 "rev": 0
678 }
678 }
679 ]
679 ]
680
680
681 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
681 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
682 c
682 c
683
683
684 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
684 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
685 md: merge head 2
685 md: merge head 2
686 b: reopen branch with a change
686 b: reopen branch with a change
687 a: Adding d branch
687 a: Adding d branch
688 m: head 2
688 m: head 2
689 a: Adding b branch head 2
689 a: Adding b branch head 2
690 default: Adding root node
690 default: Adding root node
691
691
692 $ cat <<'EOF' > "$TESTTMP/map-myjson"
692 $ cat <<'EOF' > "$TESTTMP/map-myjson"
693 > docheader = '\{\n'
693 > docheader = '\{\n'
694 > docfooter = '\n}\n'
694 > docfooter = '\n}\n'
695 > separator = ',\n'
695 > separator = ',\n'
696 > branches = ' {dict(branch, node|short)|json}'
696 > branches = ' {dict(branch, node|short)|json}'
697 > EOF
697 > EOF
698 $ hg branches -T "$TESTTMP/map-myjson"
698 $ hg branches -T "$TESTTMP/map-myjson"
699 {
699 {
700 {"branch": "md", "node": "c914c99f1fbb"},
700 {"branch": "md", "node": "c914c99f1fbb"},
701 {"branch": "b", "node": "e23b5505d1ad"},
701 {"branch": "b", "node": "e23b5505d1ad"},
702 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
702 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
703 {"branch": "m", "node": "df343b0df04f"},
703 {"branch": "m", "node": "df343b0df04f"},
704 {"branch": "a", "node": "d8cbc61dbaa6"},
704 {"branch": "a", "node": "d8cbc61dbaa6"},
705 {"branch": "default", "node": "19709c5a4e75"}
705 {"branch": "default", "node": "19709c5a4e75"}
706 }
706 }
707
707
708 $ cat <<'EOF' >> .hg/hgrc
708 $ cat <<'EOF' >> .hg/hgrc
709 > [templates]
709 > [templates]
710 > myjson = ' {dict(branch, node|short)|json}'
710 > myjson = ' {dict(branch, node|short)|json}'
711 > myjson:docheader = '\{\n'
711 > myjson:docheader = '\{\n'
712 > myjson:docfooter = '\n}\n'
712 > myjson:docfooter = '\n}\n'
713 > myjson:separator = ',\n'
713 > myjson:separator = ',\n'
714 > EOF
714 > EOF
715 $ hg branches -T myjson
715 $ hg branches -T myjson
716 {
716 {
717 {"branch": "md", "node": "c914c99f1fbb"},
717 {"branch": "md", "node": "c914c99f1fbb"},
718 {"branch": "b", "node": "e23b5505d1ad"},
718 {"branch": "b", "node": "e23b5505d1ad"},
719 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
719 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
720 {"branch": "m", "node": "df343b0df04f"},
720 {"branch": "m", "node": "df343b0df04f"},
721 {"branch": "a", "node": "d8cbc61dbaa6"},
721 {"branch": "a", "node": "d8cbc61dbaa6"},
722 {"branch": "default", "node": "19709c5a4e75"}
722 {"branch": "default", "node": "19709c5a4e75"}
723 }
723 }
724
724
725 $ cat <<'EOF' >> .hg/hgrc
725 $ cat <<'EOF' >> .hg/hgrc
726 > [templates]
726 > [templates]
727 > :docheader = 'should not be selected as a docheader for literal templates\n'
727 > :docheader = 'should not be selected as a docheader for literal templates\n'
728 > EOF
728 > EOF
729 $ hg branches -T '{branch}\n'
729 $ hg branches -T '{branch}\n'
730 md
730 md
731 b
731 b
732 a branch name much longer than the default justification used by branches
732 a branch name much longer than the default justification used by branches
733 m
733 m
734 a
734 a
735 default
735 default
736
736
737 Tests of revision branch name caching
737 Tests of revision branch name caching
738
738
739 We rev branch cache is updated automatically. In these tests we use a trick to
739 We rev branch cache is updated automatically. In these tests we use a trick to
740 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
740 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
741 rebuild that also will populate the rev branch cache.
741 rebuild that also will populate the rev branch cache.
742
742
743 revision branch cache is created when building the branch head cache
743 revision branch cache is created when building the branch head cache
744 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
744 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
745 5
745 5
746 $ f --hexdump --size .hg/cache/rbc-*
746 $ f --hexdump --size .hg/cache/rbc-*
747 .hg/cache/rbc-names-v1: size=92
747 .hg/cache/rbc-names-v1: size=92
748 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
748 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
749 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
749 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
750 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
750 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
751 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
751 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
752 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
752 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
753 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
753 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
754 .hg/cache/rbc-revs-v1: size=160
754 .hg/cache/rbc-revs-v1: size=160
755 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
755 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
756 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
756 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
757 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
757 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
758 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
758 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
759 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
759 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
760 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
760 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
761 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
761 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
762 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
762 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
763 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
763 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
764 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
764 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
765
765
766 no errors when revbranchcache is not writable
766 no errors when revbranchcache is not writable
767
767
768 $ echo >> .hg/cache/rbc-revs-v1
768 $ echo >> .hg/cache/rbc-revs-v1
769 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
769 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
770 $ mkdir .hg/cache/rbc-revs-v1
770 $ mkdir .hg/cache/rbc-revs-v1
771 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
771 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
772 5
772 5
773 $ rmdir .hg/cache/rbc-revs-v1
773 $ rmdir .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
775
775
776 no errors when wlock cannot be acquired
776 no errors when wlock cannot be acquired
777
777
778 #if unix-permissions
778 #if unix-permissions
779 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
779 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
780 $ rm -f .hg/cache/branch*
780 $ rm -f .hg/cache/branch*
781 $ chmod 555 .hg
781 $ chmod 555 .hg
782 $ hg head a -T '{rev}\n'
782 $ hg head a -T '{rev}\n'
783 5
783 5
784 $ chmod 755 .hg
784 $ chmod 755 .hg
785 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
785 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
786 #endif
786 #endif
787
787
788 recovery from invalid cache revs file with trailing data
788 recovery from invalid cache revs file with trailing data
789 $ echo >> .hg/cache/rbc-revs-v1
789 $ echo >> .hg/cache/rbc-revs-v1
790 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
790 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
791 5
791 5
792 truncating cache/rbc-revs-v1 to 160
792 truncating cache/rbc-revs-v1 to 160
793 $ f --size .hg/cache/rbc-revs*
793 $ f --size .hg/cache/rbc-revs*
794 .hg/cache/rbc-revs-v1: size=160
794 .hg/cache/rbc-revs-v1: size=160
795 recovery from invalid cache file with partial last record
795 recovery from invalid cache file with partial last record
796 $ mv .hg/cache/rbc-revs-v1 .
796 $ mv .hg/cache/rbc-revs-v1 .
797 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
797 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
798 $ f --size .hg/cache/rbc-revs*
798 $ f --size .hg/cache/rbc-revs*
799 .hg/cache/rbc-revs-v1: size=119
799 .hg/cache/rbc-revs-v1: size=119
800 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
800 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
801 5
801 5
802 truncating cache/rbc-revs-v1 to 112
802 truncating cache/rbc-revs-v1 to 112
803 $ f --size .hg/cache/rbc-revs*
803 $ f --size .hg/cache/rbc-revs*
804 .hg/cache/rbc-revs-v1: size=160
804 .hg/cache/rbc-revs-v1: size=160
805 recovery from invalid cache file with missing record - no truncation
805 recovery from invalid cache file with missing record - no truncation
806 $ mv .hg/cache/rbc-revs-v1 .
806 $ mv .hg/cache/rbc-revs-v1 .
807 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
807 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
808 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
808 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
809 5
809 5
810 $ f --size .hg/cache/rbc-revs*
810 $ f --size .hg/cache/rbc-revs*
811 .hg/cache/rbc-revs-v1: size=160
811 .hg/cache/rbc-revs-v1: size=160
812 recovery from invalid cache file with some bad records
812 recovery from invalid cache file with some bad records
813 $ mv .hg/cache/rbc-revs-v1 .
813 $ mv .hg/cache/rbc-revs-v1 .
814 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
814 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
815 $ f --size .hg/cache/rbc-revs*
815 $ f --size .hg/cache/rbc-revs*
816 .hg/cache/rbc-revs-v1: size=8
816 .hg/cache/rbc-revs-v1: size=8
817 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
817 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
818 $ f --size .hg/cache/rbc-revs*
818 $ f --size .hg/cache/rbc-revs*
819 .hg/cache/rbc-revs-v1: size=120
819 .hg/cache/rbc-revs-v1: size=120
820 $ hg log -r 'branch(.)' -T '{rev} ' --debug
820 $ hg log -r 'branch(.)' -T '{rev} ' --debug
821 history modification detected - truncating revision branch cache to revision 13
821 history modification detected - truncating revision branch cache to revision 13
822 history modification detected - truncating revision branch cache to revision 1
822 history modification detected - truncating revision branch cache to revision 1
823 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
823 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
824 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
824 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
825 5
825 5
826 truncating cache/rbc-revs-v1 to 104
826 truncating cache/rbc-revs-v1 to 104
827 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
827 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
828 .hg/cache/rbc-revs-v1: size=160
828 .hg/cache/rbc-revs-v1: size=160
829 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
829 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
830 cache is updated when committing
830 cache is updated when committing
831 $ hg branch i-will-regret-this
831 $ hg branch i-will-regret-this
832 marked working directory as branch i-will-regret-this
832 marked working directory as branch i-will-regret-this
833 $ hg ci -m regrets
833 $ hg ci -m regrets
834 $ f --size .hg/cache/rbc-*
834 $ f --size .hg/cache/rbc-*
835 .hg/cache/rbc-names-v1: size=111
835 .hg/cache/rbc-names-v1: size=111
836 .hg/cache/rbc-revs-v1: size=168
836 .hg/cache/rbc-revs-v1: size=168
837 update after rollback - the cache will be correct but rbc-names will will still
837 update after rollback - the cache will be correct but rbc-names will will still
838 contain the branch name even though it no longer is used
838 contain the branch name even though it no longer is used
839 $ hg up -qr '.^'
839 $ hg up -qr '.^'
840 $ hg rollback -qf
840 $ hg rollback -qf
841 $ f --size --hexdump .hg/cache/rbc-*
841 $ f --size --hexdump .hg/cache/rbc-*
842 .hg/cache/rbc-names-v1: size=111
842 .hg/cache/rbc-names-v1: size=111
843 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
843 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
844 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
844 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
845 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
845 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
846 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
846 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
847 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
847 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
848 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
848 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
849 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
849 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
850 .hg/cache/rbc-revs-v1: size=160
850 .hg/cache/rbc-revs-v1: size=160
851 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
851 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
852 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
852 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
853 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
853 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
854 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
854 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
855 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
855 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
856 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
856 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
857 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
857 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
858 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
858 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
859 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
859 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
860 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
860 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
861 cache is updated/truncated when stripping - it is thus very hard to get in a
861 cache is updated/truncated when stripping - it is thus very hard to get in a
862 situation where the cache is out of sync and the hash check detects it
862 situation where the cache is out of sync and the hash check detects it
863 $ hg --config extensions.strip= strip -r tip --nob
863 $ hg --config extensions.strip= strip -r tip --nob
864 $ f --size .hg/cache/rbc-revs*
864 $ f --size .hg/cache/rbc-revs*
865 .hg/cache/rbc-revs-v1: size=152
865 .hg/cache/rbc-revs-v1: size=152
866
866
867 cache is rebuilt when corruption is detected
867 cache is rebuilt when corruption is detected
868 $ echo > .hg/cache/rbc-names-v1
868 $ echo > .hg/cache/rbc-names-v1
869 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
869 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
870 referenced branch names not found - rebuilding revision branch cache from scratch
870 referenced branch names not found - rebuilding revision branch cache from scratch
871 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
871 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
872 $ f --size --hexdump .hg/cache/rbc-*
872 $ f --size --hexdump .hg/cache/rbc-*
873 .hg/cache/rbc-names-v1: size=84
873 .hg/cache/rbc-names-v1: size=84
874 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
874 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
875 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
875 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
876 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
876 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
877 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
877 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
878 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
878 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
879 0050: 6d 00 6d 64 |m.md|
879 0050: 6d 00 6d 64 |m.md|
880 .hg/cache/rbc-revs-v1: size=152
880 .hg/cache/rbc-revs-v1: size=152
881 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
881 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
882 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
882 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
883 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
883 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
884 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
884 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
885 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
885 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
886 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
886 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
887 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
887 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
888 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
888 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
889 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
889 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
890 0090: c9 14 c9 9f 00 00 00 05 |........|
890 0090: c9 14 c9 9f 00 00 00 05 |........|
891
891
892 Test that cache files are created and grows correctly:
892 Test that cache files are created and grows correctly:
893
893
894 $ rm .hg/cache/rbc*
894 $ rm .hg/cache/rbc*
895 $ hg log -r "5 & branch(5)" -T "{rev}\n"
895 $ hg log -r "5 & branch(5)" -T "{rev}\n"
896 5
896 5
897 $ f --size --hexdump .hg/cache/rbc-*
897 $ f --size --hexdump .hg/cache/rbc-*
898 .hg/cache/rbc-names-v1: size=1
898 .hg/cache/rbc-names-v1: size=1
899 0000: 61 |a|
899 0000: 61 |a|
900 .hg/cache/rbc-revs-v1: size=152
900 .hg/cache/rbc-revs-v1: size=152
901 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
901 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
902 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
902 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
903 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
903 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
904 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
904 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
905 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
905 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
906 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
906 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
907 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
907 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
908 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
908 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
909 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
909 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
910 0090: 00 00 00 00 00 00 00 00 |........|
910 0090: 00 00 00 00 00 00 00 00 |........|
911
911
912 $ cd ..
912 $ cd ..
913
913
914 Test for multiple incorrect branch cache entries:
914 Test for multiple incorrect branch cache entries:
915
915
916 $ hg init b
916 $ hg init b
917 $ cd b
917 $ cd b
918 $ touch f
918 $ touch f
919 $ hg ci -Aqmf
919 $ hg ci -Aqmf
920 $ echo >> f
920 $ echo >> f
921 $ hg ci -Amf
921 $ hg ci -Amf
922 $ hg branch -q branch
922 $ hg branch -q branch
923 $ hg ci -Amf
923 $ hg ci -Amf
924
924
925 $ f --size --hexdump .hg/cache/rbc-*
925 $ f --size --hexdump .hg/cache/rbc-*
926 .hg/cache/rbc-names-v1: size=14
926 .hg/cache/rbc-names-v1: size=14
927 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
927 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
928 .hg/cache/rbc-revs-v1: size=24
928 .hg/cache/rbc-revs-v1: size=24
929 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
929 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
930 0010: 56 46 78 69 00 00 00 01 |VFxi....|
930 0010: 56 46 78 69 00 00 00 01 |VFxi....|
931 $ : > .hg/cache/rbc-revs-v1
931 $ : > .hg/cache/rbc-revs-v1
932
932
933 No superfluous rebuilding of cache:
933 No superfluous rebuilding of cache:
934 $ hg log -r "branch(null)&branch(branch)" --debug
934 $ hg log -r "branch(null)&branch(branch)" --debug
935 $ f --size --hexdump .hg/cache/rbc-*
935 $ f --size --hexdump .hg/cache/rbc-*
936 .hg/cache/rbc-names-v1: size=14
936 .hg/cache/rbc-names-v1: size=14
937 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
937 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
938 .hg/cache/rbc-revs-v1: size=24
938 .hg/cache/rbc-revs-v1: size=24
939 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
939 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
940 0010: 56 46 78 69 00 00 00 01 |VFxi....|
940 0010: 56 46 78 69 00 00 00 01 |VFxi....|
941
941
942 $ cd ..
942 $ cd ..
943
943
944 Test to make sure that `--close-branch` only works on a branch head:
944 Test to make sure that `--close-branch` only works on a branch head:
945 --------------------------------------------------------------------
945 --------------------------------------------------------------------
946 $ hg init closebranch
946 $ hg init closebranch
947 $ cd closebranch
947 $ cd closebranch
948 $ for ch in a b c; do
948 $ for ch in a b c; do
949 > echo $ch > $ch
949 > echo $ch > $ch
950 > hg add $ch
950 > hg add $ch
951 > hg ci -m "added "$ch
951 > hg ci -m "added "$ch
952 > done;
952 > done;
953
953
954 $ hg up -r "desc('added b')"
954 $ hg up -r "desc('added b')"
955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
956
956
957 trying to close branch from a cset which is not a branch head
957 trying to close branch from a cset which is not a branch head
958 it should abort:
958 it should abort:
959 $ hg ci -m "closing branch" --close-branch
959 $ hg ci -m "closing branch" --close-branch
960 abort: can only close branch heads
960 abort: can only close branch heads
961 (use --force-close-branch to close branch from a non-head changeset)
961 (use --force-close-branch to close branch from a non-head changeset)
962 [10]
962 [10]
963
963
964 $ hg up 0
964 $ hg up 0
965 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
965 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
966 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
966 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
967 o 2: 155349b645be added c
967 o 2: 155349b645be added c
968 | default
968 | default
969 |
969 |
970 o 1: 5f6d8a4bf34a added b
970 o 1: 5f6d8a4bf34a added b
971 | default
971 | default
972 |
972 |
973 @ 0: 9092f1db7931 added a
973 @ 0: 9092f1db7931 added a
974 default
974 default
975
975
976 Test --force-close-branch to close a branch from a non-head changeset:
976 Test --force-close-branch to close a branch from a non-head changeset:
977 ---------------------------------------------------------------------
977 ---------------------------------------------------------------------
978
978
979 $ hg show stack --config extensions.show=
979 $ hg show stack --config extensions.show=
980 o 1553 added c
980 o 1553 added c
981 o 5f6d added b
981 o 5f6d added b
982 @ 9092 added a
982 @ 9092 added a
983
983
984 $ hg ci -m "branch closed" --close-branch
984 $ hg ci -m "branch closed" --close-branch
985 abort: can only close branch heads
985 abort: can only close branch heads
986 (use --force-close-branch to close branch from a non-head changeset)
986 (use --force-close-branch to close branch from a non-head changeset)
987 [10]
987 [10]
988
988
989 $ hg ci -m "branch closed" --force-close-branch
989 $ hg ci -m "branch closed" --force-close-branch
990 created new head
990 created new head
991 $ cd ..
992
993 Test various special cases for the branchmap
994 --------------------------------------------
995
996 Basic fork of the same branch
997
998 $ hg init branchmap-testing1
999 $ cd branchmap-testing1
1000 $ hg debugbuild '@A . :base . :p1 *base /p1'
1001 $ hg log -G
1002 o changeset: 3:71ca9a6d524e
1003 |\ branch: A
1004 | | tag: tip
1005 | | parent: 2:a3b807b3ff0b
1006 | | parent: 1:99ba08759bc7
1007 | | user: debugbuilddag
1008 | | date: Thu Jan 01 00:00:03 1970 +0000
1009 | | summary: r3
1010 | |
1011 | o changeset: 2:a3b807b3ff0b
1012 | | branch: A
1013 | | parent: 0:2ab8003a1750
1014 | | user: debugbuilddag
1015 | | date: Thu Jan 01 00:00:02 1970 +0000
1016 | | summary: r2
1017 | |
1018 o | changeset: 1:99ba08759bc7
1019 |/ branch: A
1020 | tag: p1
1021 | user: debugbuilddag
1022 | date: Thu Jan 01 00:00:01 1970 +0000
1023 | summary: r1
1024 |
1025 o changeset: 0:2ab8003a1750
1026 branch: A
1027 tag: base
1028 user: debugbuilddag
1029 date: Thu Jan 01 00:00:00 1970 +0000
1030 summary: r0
1031
1032 $ hg branches
1033 A 3:71ca9a6d524e
1034 $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone
1035 adding changesets
1036 adding manifests
1037 adding file changes
1038 added 3 changesets with 0 changes to 0 files (+1 heads)
1039 new changesets 2ab8003a1750:a3b807b3ff0b
1040 updating to branch A
1041 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1042 $ cd ../branchmap-testing1-clone
1043 $ hg pull ../branchmap-testing1
1044 pulling from ../branchmap-testing1
1045 searching for changes
1046 adding changesets
1047 adding manifests
1048 adding file changes
1049 added 1 changesets with 0 changes to 0 files (-1 heads)
1050 new changesets 71ca9a6d524e
1051 (run 'hg update' to get a working copy)
1052 $ hg branches
1053 A 3:71ca9a6d524e
1054 $ cd ..
1055
1056 Switching to a different branch and back
1057
1058 $ hg init branchmap-testing2
1059 $ cd branchmap-testing2
1060 $ hg debugbuild '@A . @B . @A .'
1061 $ hg log -G
1062 o changeset: 2:9699e9f260b5
1063 | branch: A
1064 | tag: tip
1065 | user: debugbuilddag
1066 | date: Thu Jan 01 00:00:02 1970 +0000
1067 | summary: r2
1068 |
1069 o changeset: 1:0bc7d348d965
1070 | branch: B
1071 | user: debugbuilddag
1072 | date: Thu Jan 01 00:00:01 1970 +0000
1073 | summary: r1
1074 |
1075 o changeset: 0:2ab8003a1750
1076 branch: A
1077 user: debugbuilddag
1078 date: Thu Jan 01 00:00:00 1970 +0000
1079 summary: r0
1080
1081 $ hg branches
1082 A 2:9699e9f260b5
1083 B 1:0bc7d348d965 (inactive)
1084 $ hg clone -r 1 . ../branchmap-testing2-clone
1085 adding changesets
1086 adding manifests
1087 adding file changes
1088 added 2 changesets with 0 changes to 0 files
1089 new changesets 2ab8003a1750:0bc7d348d965
1090 updating to branch B
1091 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1092 $ cd ../branchmap-testing2-clone
1093 $ hg pull ../branchmap-testing2
1094 pulling from ../branchmap-testing2
1095 searching for changes
1096 adding changesets
1097 adding manifests
1098 adding file changes
1099 added 1 changesets with 0 changes to 0 files
1100 new changesets 9699e9f260b5
1101 (run 'hg update' to get a working copy)
1102 $ hg branches
1103 A 2:9699e9f260b5
1104 B 1:0bc7d348d965 (inactive)
1105 $ cd ..
1106
1107 A fork on a branch switching to a different branch and back
1108 is still collecting the fork.
1109
1110 $ hg init branchmap-testing3
1111 $ cd branchmap-testing3
1112 $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1'
1113 $ hg log -G
1114 o changeset: 4:3614a1711d23
1115 |\ branch: A
1116 | | tag: tip
1117 | | parent: 3:e9c8abcf65aa
1118 | | parent: 1:99ba08759bc7
1119 | | user: debugbuilddag
1120 | | date: Thu Jan 01 00:00:04 1970 +0000
1121 | | summary: r4
1122 | |
1123 | o changeset: 3:e9c8abcf65aa
1124 | | branch: B
1125 | | user: debugbuilddag
1126 | | date: Thu Jan 01 00:00:03 1970 +0000
1127 | | summary: r3
1128 | |
1129 | o changeset: 2:a3b807b3ff0b
1130 | | branch: A
1131 | | parent: 0:2ab8003a1750
1132 | | user: debugbuilddag
1133 | | date: Thu Jan 01 00:00:02 1970 +0000
1134 | | summary: r2
1135 | |
1136 o | changeset: 1:99ba08759bc7
1137 |/ branch: A
1138 | tag: p1
1139 | user: debugbuilddag
1140 | date: Thu Jan 01 00:00:01 1970 +0000
1141 | summary: r1
1142 |
1143 o changeset: 0:2ab8003a1750
1144 branch: A
1145 tag: base
1146 user: debugbuilddag
1147 date: Thu Jan 01 00:00:00 1970 +0000
1148 summary: r0
1149
1150 $ hg branches
1151 A 4:3614a1711d23
1152 B 3:e9c8abcf65aa (inactive)
1153 $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone
1154 adding changesets
1155 adding manifests
1156 adding file changes
1157 added 4 changesets with 0 changes to 0 files (+1 heads)
1158 new changesets 2ab8003a1750:e9c8abcf65aa
1159 updating to branch A
1160 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1161 $ cd ../branchmap-testing3-clone
1162 $ hg pull ../branchmap-testing3
1163 pulling from ../branchmap-testing3
1164 searching for changes
1165 adding changesets
1166 adding manifests
1167 adding file changes
1168 added 1 changesets with 0 changes to 0 files (-1 heads)
1169 new changesets 3614a1711d23
1170 (run 'hg update' to get a working copy)
1171 $ hg branches
1172 A 4:3614a1711d23
1173 B 3:e9c8abcf65aa (inactive)
1174 $ cd ..
1175
1176 Intermediary parents are on different branches.
1177
1178 $ hg init branchmap-testing4
1179 $ cd branchmap-testing4
1180 $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1'
1181 $ hg log -G
1182 o changeset: 4:4bf67499b70a
1183 |\ branch: A
1184 | | tag: tip
1185 | | parent: 3:4a546028fa8f
1186 | | parent: 1:0bc7d348d965
1187 | | user: debugbuilddag
1188 | | date: Thu Jan 01 00:00:04 1970 +0000
1189 | | summary: r4
1190 | |
1191 | o changeset: 3:4a546028fa8f
1192 | | branch: C
1193 | | user: debugbuilddag
1194 | | date: Thu Jan 01 00:00:03 1970 +0000
1195 | | summary: r3
1196 | |
1197 | o changeset: 2:a3b807b3ff0b
1198 | | branch: A
1199 | | parent: 0:2ab8003a1750
1200 | | user: debugbuilddag
1201 | | date: Thu Jan 01 00:00:02 1970 +0000
1202 | | summary: r2
1203 | |
1204 o | changeset: 1:0bc7d348d965
1205 |/ branch: B
1206 | tag: p1
1207 | user: debugbuilddag
1208 | date: Thu Jan 01 00:00:01 1970 +0000
1209 | summary: r1
1210 |
1211 o changeset: 0:2ab8003a1750
1212 branch: A
1213 tag: base
1214 user: debugbuilddag
1215 date: Thu Jan 01 00:00:00 1970 +0000
1216 summary: r0
1217
1218 $ hg branches
1219 A 4:4bf67499b70a
1220 C 3:4a546028fa8f (inactive)
1221 B 1:0bc7d348d965 (inactive)
1222 $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone
1223 adding changesets
1224 adding manifests
1225 adding file changes
1226 added 4 changesets with 0 changes to 0 files (+1 heads)
1227 new changesets 2ab8003a1750:4a546028fa8f
1228 updating to branch B
1229 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1230 $ cd ../branchmap-testing4-clone
1231 $ hg pull ../branchmap-testing4
1232 pulling from ../branchmap-testing4
1233 searching for changes
1234 adding changesets
1235 adding manifests
1236 adding file changes
1237 added 1 changesets with 0 changes to 0 files (-1 heads)
1238 new changesets 4bf67499b70a
1239 (run 'hg update' to get a working copy)
1240 $ hg branches
1241 A 4:4bf67499b70a
1242 C 3:4a546028fa8f (inactive)
1243 B 1:0bc7d348d965 (inactive)
1244 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now