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