##// END OF EJS Templates
Add searching for named branches...
mason@suse.com -
r898:3616c0d7 default
parent child Browse files
Show More
@@ -194,7 +194,7 b' def dodiff(fp, ui, repo, files=None, nod'
194 194 tn = None
195 195 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
196 196
197 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
197 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
198 198 """show a single changeset or file revision"""
199 199 changelog = repo.changelog
200 200 if filelog:
@@ -236,6 +236,10 b' def show_changeset(ui, repo, rev=0, chan'
236 236 if filelog:
237 237 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
238 238
239 if brinfo and changenode in brinfo:
240 br = brinfo[changenode]
241 ui.write("branch: %s\n" % " ".join(br))
242
239 243 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
240 244 hg.hex(changes[0])))
241 245 ui.status("user: %s\n" % changes[1])
@@ -675,10 +679,14 b' def forget(ui, repo, *pats, **opts):'
675 679 if rel not in q: ui.status('forgetting ', rel, '\n')
676 680 repo.forget(forget)
677 681
678 def heads(ui, repo):
682 def heads(ui, repo, **opts):
679 683 """show current repository heads"""
684 heads = repo.changelog.heads()
685 br = None
686 if opts['branches']:
687 br = repo.branchlookup(heads)
680 688 for n in repo.changelog.heads():
681 show_changeset(ui, repo, changenode=n)
689 show_changeset(ui, repo, changenode=n, brinfo=br)
682 690
683 691 def identify(ui, repo):
684 692 """print information about the working copy"""
@@ -1150,7 +1158,7 b' def undo(ui, repo):'
1150 1158 """
1151 1159 repo.undo()
1152 1160
1153 def update(ui, repo, node=None, merge=False, clean=False):
1161 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1154 1162 '''update or merge working directory
1155 1163
1156 1164 If there are no outstanding changes in the working directory and
@@ -1163,7 +1171,25 b' def update(ui, repo, node=None, merge=Fa'
1163 1171 commit and a commit must be performed before any further updates
1164 1172 are allowed.
1165 1173 '''
1166 node = node and repo.lookup(node) or repo.changelog.tip()
1174 if branch:
1175 br = repo.branchlookup(branch=branch)
1176 found = []
1177 for x in br:
1178 if branch in br[x]:
1179 found.append(x)
1180 if len(found) > 1:
1181 ui.warn("Found multiple heads for %s\n" % branch)
1182 for x in found:
1183 show_changeset(ui, repo, changenode=x, brinfo=br)
1184 return 1
1185 if len(found) == 1:
1186 node = found[0]
1187 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1188 else:
1189 ui.warn("branch %s not found\n" % (branch))
1190 return 1
1191 else:
1192 node = node and repo.lookup(node) or repo.changelog.tip()
1167 1193 return repo.update(node, allow=merge, force=clean)
1168 1194
1169 1195 def verify(ui, repo):
@@ -1236,7 +1262,7 b' table = {'
1236 1262 [('I', 'include', [], 'include path in search'),
1237 1263 ('X', 'exclude', [], 'exclude path from search')],
1238 1264 "hg forget FILE..."),
1239 "heads": (heads, [], 'hg heads'),
1265 "heads": (heads, [('b', 'branches', None, 'find branch info')], 'hg heads'),
1240 1266 "help": (help_, [], 'hg help [COMMAND]'),
1241 1267 "identify|id": (identify, [], 'hg identify'),
1242 1268 "import|patch":
@@ -1320,7 +1346,8 b' table = {'
1320 1346 "undo": (undo, [], 'hg undo'),
1321 1347 "^update|up|checkout|co":
1322 1348 (update,
1323 [('m', 'merge', None, 'allow merging of conflicts'),
1349 [('b', 'branch', "", 'checkout the head of a specific branch'),
1350 ('m', 'merge', None, 'allow merging of conflicts'),
1324 1351 ('C', 'clean', None, 'overwrite locally modified files')],
1325 1352 'hg update [-m] [-C] [REV]'),
1326 1353 "verify": (verify, [], 'hg verify'),
@@ -1072,6 +1072,112 b' class localrepository:'
1072 1072 def heads(self):
1073 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 1181 def branches(self, nodes):
1076 1182 if not nodes: nodes = [self.changelog.tip()]
1077 1183 b = []
General Comments 0
You need to be logged in to leave comments. Login now