Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/hg.py @ 898:3616c0d7ab88
Add searching for named branches
named branching is when you identify a head by a tag on an earlier revision.
This patch adds repo.branchlookup for searching through the tree to
find branch tags for heads.
hg update -b tag is added to checkout based on branch tags
hg heads -b is added to print the tag associated with each head
author | mason@suse.com |
---|---|
date | Sun, 14 Aug 2005 12:23:45 -0800 |
parents | 01215ad04283 |
children | ba8cf1f2210c |
comparison
equal
deleted
inserted
replaced
897:fe30f5434b51 | 898:3616c0d7ab88 |
---|---|
1070 self.dirstate.copy(source, dest) | 1070 self.dirstate.copy(source, dest) |
1071 | 1071 |
1072 def heads(self): | 1072 def heads(self): |
1073 return self.changelog.heads() | 1073 return self.changelog.heads() |
1074 | 1074 |
1075 # branchlookup returns a dict giving a list of branches for | |
1076 # each head. A branch is defined as the tag of a node or | |
1077 # the branch of the node's parents. If a node has multiple | |
1078 # branch tags, tags are eliminated if they are visible from other | |
1079 # branch tags. | |
1080 # | |
1081 # So, for this graph: a->b->c->d->e | |
1082 # \ / | |
1083 # aa -----/ | |
1084 # a has tag 2.6.12 | |
1085 # d has tag 2.6.13 | |
1086 # e would have branch tags for 2.6.12 and 2.6.13. Because the node | |
1087 # for 2.6.12 can be reached from the node 2.6.13, that is eliminated | |
1088 # from the list. | |
1089 # | |
1090 # It is possible that more than one head will have the same branch tag. | |
1091 # callers need to check the result for multiple heads under the same | |
1092 # branch tag if that is a problem for them (ie checkout of a specific | |
1093 # branch). | |
1094 # | |
1095 # passing in a specific branch will limit the depth of the search | |
1096 # through the parents. It won't limit the branches returned in the | |
1097 # result though. | |
1098 def branchlookup(self, heads=None, branch=None): | |
1099 if not heads: | |
1100 heads = self.heads() | |
1101 headt = [ h for h in heads ] | |
1102 chlog = self.changelog | |
1103 branches = {} | |
1104 merges = [] | |
1105 seenmerge = {} | |
1106 | |
1107 # traverse the tree once for each head, recording in the branches | |
1108 # dict which tags are visible from this head. The branches | |
1109 # dict also records which tags are visible from each tag | |
1110 # while we traverse. | |
1111 while headt or merges: | |
1112 if merges: | |
1113 n, found = merges.pop() | |
1114 visit = [n] | |
1115 else: | |
1116 h = headt.pop() | |
1117 visit = [h] | |
1118 found = [h] | |
1119 seen = {} | |
1120 while visit: | |
1121 n = visit.pop() | |
1122 if n in seen: | |
1123 continue | |
1124 pp = chlog.parents(n) | |
1125 tags = self.nodetags(n) | |
1126 if tags: | |
1127 for x in tags: | |
1128 if x == 'tip': | |
1129 continue | |
1130 for f in found: | |
1131 branches.setdefault(f, {})[n] = 1 | |
1132 branches.setdefault(n, {})[n] = 1 | |
1133 break | |
1134 if n not in found: | |
1135 found.append(n) | |
1136 if branch in tags: | |
1137 continue | |
1138 seen[n] = 1 | |
1139 if pp[1] != nullid and n not in seenmerge: | |
1140 merges.append((pp[1], [x for x in found])) | |
1141 seenmerge[n] = 1 | |
1142 if pp[0] != nullid: | |
1143 visit.append(pp[0]) | |
1144 # traverse the branches dict, eliminating branch tags from each | |
1145 # head that are visible from another branch tag for that head. | |
1146 out = {} | |
1147 viscache = {} | |
1148 for h in heads: | |
1149 def visible(node): | |
1150 if node in viscache: | |
1151 return viscache[node] | |
1152 ret = {} | |
1153 visit = [node] | |
1154 while visit: | |
1155 x = visit.pop() | |
1156 if x in viscache: | |
1157 ret.update(viscache[x]) | |
1158 elif x not in ret: | |
1159 ret[x] = 1 | |
1160 if x in branches: | |
1161 visit[len(visit):] = branches[x].keys() | |
1162 viscache[node] = ret | |
1163 return ret | |
1164 if h not in branches: | |
1165 continue | |
1166 # O(n^2), but somewhat limited. This only searches the | |
1167 # tags visible from a specific head, not all the tags in the | |
1168 # whole repo. | |
1169 for b in branches[h]: | |
1170 vis = False | |
1171 for bb in branches[h].keys(): | |
1172 if b != bb: | |
1173 if b in visible(bb): | |
1174 vis = True | |
1175 break | |
1176 if not vis: | |
1177 l = out.setdefault(h, []) | |
1178 l[len(l):] = self.nodetags(b) | |
1179 return out | |
1180 | |
1075 def branches(self, nodes): | 1181 def branches(self, nodes): |
1076 if not nodes: nodes = [self.changelog.tip()] | 1182 if not nodes: nodes = [self.changelog.tip()] |
1077 b = [] | 1183 b = [] |
1078 for n in nodes: | 1184 for n in nodes: |
1079 t = n | 1185 t = n |