##// END OF EJS Templates
store all heads of a branch in the branch cache...
John Mulligan -
r7654:816b708f default
parent child Browse files
Show More
@@ -360,6 +360,7 b' class localrepository(repo.repository):'
360 return self.nodetagscache.get(node, [])
360 return self.nodetagscache.get(node, [])
361
361
362 def _branchtags(self, partial, lrev):
362 def _branchtags(self, partial, lrev):
363 # TODO: rename this function?
363 tiprev = len(self) - 1
364 tiprev = len(self) - 1
364 if lrev != tiprev:
365 if lrev != tiprev:
365 self._updatebranchcache(partial, lrev+1, tiprev+1)
366 self._updatebranchcache(partial, lrev+1, tiprev+1)
@@ -367,7 +368,7 b' class localrepository(repo.repository):'
367
368
368 return partial
369 return partial
369
370
370 def branchtags(self):
371 def _branchheads(self):
371 tip = self.changelog.tip()
372 tip = self.changelog.tip()
372 if self.branchcache is not None and self._branchcachetip == tip:
373 if self.branchcache is not None and self._branchcachetip == tip:
373 return self.branchcache
374 return self.branchcache
@@ -385,18 +386,25 b' class localrepository(repo.repository):'
385 partial = self._ubranchcache
386 partial = self._ubranchcache
386
387
387 self._branchtags(partial, lrev)
388 self._branchtags(partial, lrev)
389 # this private cache holds all heads (not just tips)
390 self._ubranchcache = partial
388
391
389 # the branch cache is stored on disk as UTF-8, but in the local
392 # the branch cache is stored on disk as UTF-8, but in the local
390 # charset internally
393 # charset internally
391 for k, v in partial.iteritems():
394 for k, v in partial.iteritems():
392 self.branchcache[util.tolocal(k)] = v
395 self.branchcache[util.tolocal(k)] = v
393 self._ubranchcache = partial
394 return self.branchcache
396 return self.branchcache
395
397
398
399 def branchtags(self):
400 '''return a dict where branch names map to the tipmost head of
401 the branch'''
402 return dict([(k, v[-1]) for (k, v) in self._branchheads().iteritems()])
403
396 def _readbranchcache(self):
404 def _readbranchcache(self):
397 partial = {}
405 partial = {}
398 try:
406 try:
399 f = self.opener("branch.cache")
407 f = self.opener("branchheads.cache")
400 lines = f.read().split('\n')
408 lines = f.read().split('\n')
401 f.close()
409 f.close()
402 except (IOError, OSError):
410 except (IOError, OSError):
@@ -411,7 +419,7 b' class localrepository(repo.repository):'
411 for l in lines:
419 for l in lines:
412 if not l: continue
420 if not l: continue
413 node, label = l.split(" ", 1)
421 node, label = l.split(" ", 1)
414 partial[label.strip()] = bin(node)
422 partial.setdefault(label.strip(), []).append(bin(node))
415 except KeyboardInterrupt:
423 except KeyboardInterrupt:
416 raise
424 raise
417 except Exception, inst:
425 except Exception, inst:
@@ -422,10 +430,11 b' class localrepository(repo.repository):'
422
430
423 def _writebranchcache(self, branches, tip, tiprev):
431 def _writebranchcache(self, branches, tip, tiprev):
424 try:
432 try:
425 f = self.opener("branch.cache", "w", atomictemp=True)
433 f = self.opener("branchheads.cache", "w", atomictemp=True)
426 f.write("%s %s\n" % (hex(tip), tiprev))
434 f.write("%s %s\n" % (hex(tip), tiprev))
427 for label, node in branches.iteritems():
435 for label, nodes in branches.iteritems():
428 f.write("%s %s\n" % (hex(node), label))
436 for node in nodes:
437 f.write("%s %s\n" % (hex(node), label))
429 f.rename()
438 f.rename()
430 except (IOError, OSError):
439 except (IOError, OSError):
431 pass
440 pass
@@ -434,7 +443,12 b' class localrepository(repo.repository):'
434 for r in xrange(start, end):
443 for r in xrange(start, end):
435 c = self[r]
444 c = self[r]
436 b = c.branch()
445 b = c.branch()
437 partial[b] = c.node()
446 bheads = partial.setdefault(b, [])
447 bheads.append(c.node())
448 for p in c.parents():
449 pn = p.node()
450 if pn in bheads:
451 bheads.remove(pn)
438
452
439 def lookup(self, key):
453 def lookup(self, key):
440 if isinstance(key, int):
454 if isinstance(key, int):
@@ -1171,50 +1185,16 b' class localrepository(repo.repository):'
1171 def branchheads(self, branch=None, start=None):
1185 def branchheads(self, branch=None, start=None):
1172 if branch is None:
1186 if branch is None:
1173 branch = self[None].branch()
1187 branch = self[None].branch()
1174 branches = self.branchtags()
1188 branches = self._branchheads()
1175 if branch not in branches:
1189 if branch not in branches:
1176 return []
1190 return []
1177 # The basic algorithm is this:
1191 bheads = branches[branch]
1178 #
1192 # the cache returns heads ordered lowest to highest
1179 # Start from the branch tip since there are no later revisions that can
1193 bheads.reverse()
1180 # possibly be in this branch, and the tip is a guaranteed head.
1181 #
1182 # Remember the tip's parents as the first ancestors, since these by
1183 # definition are not heads.
1184 #
1185 # Step backwards from the brach tip through all the revisions. We are
1186 # guaranteed by the rules of Mercurial that we will now be visiting the
1187 # nodes in reverse topological order (children before parents).
1188 #
1189 # If a revision is one of the ancestors of a head then we can toss it
1190 # out of the ancestors set (we've already found it and won't be
1191 # visiting it again) and put its parents in the ancestors set.
1192 #
1193 # Otherwise, if a revision is in the branch it's another head, since it
1194 # wasn't in the ancestor list of an existing head. So add it to the
1195 # head list, and add its parents to the ancestor list.
1196 #
1197 # If it is not in the branch ignore it.
1198 #
1199 # Once we have a list of heads, use nodesbetween to filter out all the
1200 # heads that cannot be reached from startrev. There may be a more
1201 # efficient way to do this as part of the previous algorithm.
1202
1203 set = util.set
1204 heads = [self.changelog.rev(branches[branch])]
1205 # Don't care if ancestors contains nullrev or not.
1206 ancestors = set(self.changelog.parentrevs(heads[0]))
1207 for rev in xrange(heads[0] - 1, nullrev, -1):
1208 if rev in ancestors:
1209 ancestors.update(self.changelog.parentrevs(rev))
1210 ancestors.remove(rev)
1211 elif self[rev].branch() == branch:
1212 heads.append(rev)
1213 ancestors.update(self.changelog.parentrevs(rev))
1214 heads = [self.changelog.node(rev) for rev in heads]
1215 if start is not None:
1194 if start is not None:
1216 heads = self.changelog.nodesbetween([start], heads)[2]
1195 # filter out the heads that cannot be reached from startrev
1217 return heads
1196 bheads = self.changelog.nodesbetween([start], bheads)[2]
1197 return bheads
1218
1198
1219 def branches(self, nodes):
1199 def branches(self, nodes):
1220 if not nodes:
1200 if not nodes:
@@ -41,7 +41,7 b' 00770 ../push/.hg/store/'
41 % group can still write everything
41 % group can still write everything
42 00770 ../push/.hg/
42 00770 ../push/.hg/
43 00660 ../push/.hg/00changelog.i
43 00660 ../push/.hg/00changelog.i
44 00660 ../push/.hg/branch.cache
44 00660 ../push/.hg/branchheads.cache
45 00660 ../push/.hg/requires
45 00660 ../push/.hg/requires
46 00770 ../push/.hg/store/
46 00770 ../push/.hg/store/
47 00660 ../push/.hg/store/00changelog.i
47 00660 ../push/.hg/store/00changelog.i
@@ -1,6 +1,6 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 branches=.hg/branch.cache
3 branches=.hg/branchheads.cache
4 echo '[extensions]' >> $HGRCPATH
4 echo '[extensions]' >> $HGRCPATH
5 echo 'hgext.mq=' >> $HGRCPATH
5 echo 'hgext.mq=' >> $HGRCPATH
6
6
@@ -1,6 +1,6 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 branchcache=.hg/branch.cache
3 branchcache=.hg/branchheads.cache
4
4
5 hg init t
5 hg init t
6 cd t
6 cd t
@@ -81,6 +81,7 b' modify a branch'
81
81
82 4:4909a3732169
82 4:4909a3732169
83 4909a3732169c0c20011c4f4b8fdff4e3d89b23f 4
83 4909a3732169c0c20011c4f4b8fdff4e3d89b23f 4
84 be8523e69bf892e25817fc97187516b3c0804ae4 default
84 bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default
85 bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default
85 4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo
86 4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo
86 67ec16bde7f1575d523313b9bca000f6a6f12dca bar
87 67ec16bde7f1575d523313b9bca000f6a6f12dca bar
@@ -90,6 +91,7 b' be8523e69bf892e25817fc97187516b3c0804ae4'
90 be8523e69bf892e25817fc97187516b3c0804ae4 default
91 be8523e69bf892e25817fc97187516b3c0804ae4 default
91 % pushing everything
92 % pushing everything
92 4909a3732169c0c20011c4f4b8fdff4e3d89b23f 4
93 4909a3732169c0c20011c4f4b8fdff4e3d89b23f 4
94 be8523e69bf892e25817fc97187516b3c0804ae4 default
93 bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default
95 bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default
94 4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo
96 4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo
95 67ec16bde7f1575d523313b9bca000f6a6f12dca bar
97 67ec16bde7f1575d523313b9bca000f6a6f12dca bar
General Comments 0
You need to be logged in to leave comments. Login now