comparison mercurial/branchmap.py @ 18120:88990d3e3d75

branchmap: extract _updatebranchcache from repo
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Wed, 19 Dec 2012 14:49:06 +0100
parents e70ff1e599f4
children f8a13f061a8a
comparison
equal deleted inserted replaced
18119:5264464b5f68 18120:88990d3e3d75
48 for node in nodes: 48 for node in nodes:
49 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label))) 49 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
50 f.close() 50 f.close()
51 except (IOError, OSError): 51 except (IOError, OSError):
52 pass 52 pass
53
54 def update(repo, partial, ctxgen):
55 """Given a branchhead cache, partial, that may have extra nodes or be
56 missing heads, and a generator of nodes that are at least a superset of
57 heads missing, this function updates partial to be correct.
58 """
59 # collect new branch entries
60 newbranches = {}
61 for c in ctxgen:
62 newbranches.setdefault(c.branch(), []).append(c.node())
63 # if older branchheads are reachable from new ones, they aren't
64 # really branchheads. Note checking parents is insufficient:
65 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
66 for branch, newnodes in newbranches.iteritems():
67 bheads = partial.setdefault(branch, [])
68 # Remove candidate heads that no longer are in the repo (e.g., as
69 # the result of a strip that just happened). Avoid using 'node in
70 # self' here because that dives down into branchcache code somewhat
71 # recursively.
72 bheadrevs = [repo.changelog.rev(node) for node in bheads
73 if repo.changelog.hasnode(node)]
74 newheadrevs = [repo.changelog.rev(node) for node in newnodes
75 if repo.changelog.hasnode(node)]
76 ctxisnew = bheadrevs and min(newheadrevs) > max(bheadrevs)
77 # Remove duplicates - nodes that are in newheadrevs and are already
78 # in bheadrevs. This can happen if you strip a node whose parent
79 # was already a head (because they're on different branches).
80 bheadrevs = sorted(set(bheadrevs).union(newheadrevs))
81
82 # Starting from tip means fewer passes over reachable. If we know
83 # the new candidates are not ancestors of existing heads, we don't
84 # have to examine ancestors of existing heads
85 if ctxisnew:
86 iterrevs = sorted(newheadrevs)
87 else:
88 iterrevs = list(bheadrevs)
89
90 # This loop prunes out two kinds of heads - heads that are
91 # superseded by a head in newheadrevs, and newheadrevs that are not
92 # heads because an existing head is their descendant.
93 while iterrevs:
94 latest = iterrevs.pop()
95 if latest not in bheadrevs:
96 continue
97 ancestors = set(repo.changelog.ancestors([latest],
98 bheadrevs[0]))
99 if ancestors:
100 bheadrevs = [b for b in bheadrevs if b not in ancestors]
101 partial[branch] = [repo.changelog.node(rev) for rev in bheadrevs]
102
103 # There may be branches that cease to exist when the last commit in the
104 # branch was stripped. This code filters them out. Note that the
105 # branch that ceased to exist may not be in newbranches because
106 # newbranches is the set of candidate heads, which when you strip the
107 # last commit in a branch will be the parent branch.
108 for branch in partial.keys():
109 nodes = [head for head in partial[branch]
110 if repo.changelog.hasnode(head)]
111 if not nodes:
112 del partial[branch]
113