Show More
@@ -443,33 +443,82 b' class branchcache(object):' | |||||
443 | if closesbranch: |
|
443 | if closesbranch: | |
444 | self._closednodes.add(cl.node(r)) |
|
444 | self._closednodes.add(cl.node(r)) | |
445 |
|
445 | |||
446 | # fetch current topological heads to speed up filtering |
|
|||
447 | topoheads = set(cl.headrevs()) |
|
|||
448 |
|
||||
449 | # new tip revision which we found after iterating items from new |
|
446 | # new tip revision which we found after iterating items from new | |
450 | # branches |
|
447 | # branches | |
451 | ntiprev = self.tiprev |
|
448 | ntiprev = self.tiprev | |
452 |
|
449 | |||
453 | # if older branchheads are reachable from new ones, they aren't |
|
450 | # Delay fetching the topological heads until they are needed. | |
454 | # really branchheads. Note checking parents is insufficient: |
|
451 | # A repository without non-continous branches can skip this part. | |
455 | # 1 (branch a) -> 2 (branch b) -> 3 (branch a) |
|
452 | topoheads = None | |
|
453 | ||||
|
454 | # If a changeset is visible, its parents must be visible too, so | |||
|
455 | # use the faster unfiltered parent accessor. | |||
|
456 | parentrevs = repo.unfiltered().changelog.parentrevs | |||
|
457 | ||||
456 | for branch, newheadrevs in pycompat.iteritems(newbranches): |
|
458 | for branch, newheadrevs in pycompat.iteritems(newbranches): | |
|
459 | # For every branch, compute the new branchheads. | |||
|
460 | # A branchhead is a revision such that no descendant is on | |||
|
461 | # the same branch. | |||
|
462 | # | |||
|
463 | # The branchheads are computed iteratively in revision order. | |||
|
464 | # This ensures topological order, i.e. parents are processed | |||
|
465 | # before their children. Ancestors are inclusive here, i.e. | |||
|
466 | # any revision is an ancestor of itself. | |||
|
467 | # | |||
|
468 | # Core observations: | |||
|
469 | # - The current revision is always a branchhead for the | |||
|
470 | # repository up to that point. | |||
|
471 | # - It is the first revision of the branch if and only if | |||
|
472 | # there was no branchhead before. In that case, it is the | |||
|
473 | # only branchhead as there are no possible ancestors on | |||
|
474 | # the same branch. | |||
|
475 | # - If a parent is on the same branch, a branchhead can | |||
|
476 | # only be an ancestor of that parent, if it is parent | |||
|
477 | # itself. Otherwise it would have been removed as ancestor | |||
|
478 | # of that parent before. | |||
|
479 | # - Therefore, if all parents are on the same branch, they | |||
|
480 | # can just be removed from the branchhead set. | |||
|
481 | # - If one parent is on the same branch and the other is not | |||
|
482 | # and there was exactly one branchhead known, the existing | |||
|
483 | # branchhead can only be an ancestor if it is the parent. | |||
|
484 | # Otherwise it would have been removed as ancestor of | |||
|
485 | # the parent before. The other parent therefore can't have | |||
|
486 | # a branchhead as ancestor. | |||
|
487 | # - In all other cases, the parents on different branches | |||
|
488 | # could have a branchhead as ancestor. Those parents are | |||
|
489 | # kept in the "uncertain" set. If all branchheads are also | |||
|
490 | # topological heads, they can't have descendants and further | |||
|
491 | # checks can be skipped. Otherwise, the ancestors of the | |||
|
492 | # "uncertain" set are removed from branchheads. | |||
|
493 | # This computation is heavy and avoided if at all possible. | |||
457 | bheads = self._entries.setdefault(branch, []) |
|
494 | bheads = self._entries.setdefault(branch, []) | |
458 | bheadset = {cl.rev(node) for node in bheads} |
|
495 | bheadset = {cl.rev(node) for node in bheads} | |
459 |
|
496 | uncertain = set() | ||
460 | # This have been tested True on all internal usage of this function. |
|
497 | for newrev in sorted(newheadrevs): | |
461 | # run it again in case of doubt |
|
498 | if not bheadset: | |
462 |
|
|
499 | bheadset.add(newrev) | |
463 | bheadset.update(newheadrevs) |
|
500 | continue | |
464 |
|
501 | |||
465 | # This prunes out two kinds of heads - heads that are superseded by |
|
502 | parents = [p for p in parentrevs(newrev) if p != nullrev] | |
466 | # a head in newheadrevs, and newheadrevs that are not heads because |
|
503 | samebranch = set() | |
467 | # an existing head is their descendant. |
|
504 | otherbranch = set() | |
468 | uncertain = bheadset - topoheads |
|
505 | for p in parents: | |
|
506 | if p in bheadset or getbranchinfo(p)[0] == branch: | |||
|
507 | samebranch.add(p) | |||
|
508 | else: | |||
|
509 | otherbranch.add(p) | |||
|
510 | if otherbranch and not (len(bheadset) == len(samebranch) == 1): | |||
|
511 | uncertain.update(otherbranch) | |||
|
512 | bheadset.difference_update(samebranch) | |||
|
513 | bheadset.add(newrev) | |||
|
514 | ||||
469 | if uncertain: |
|
515 | if uncertain: | |
470 |
f |
|
516 | if topoheads is None: | |
471 |
|
|
517 | topoheads = set(cl.headrevs()) | |
472 |
bheadset - |
|
518 | if bheadset - topoheads: | |
|
519 | floorrev = min(bheadset) | |||
|
520 | ancestors = set(cl.ancestors(newheadrevs, floorrev)) | |||
|
521 | bheadset -= ancestors | |||
473 | bheadrevs = sorted(bheadset) |
|
522 | bheadrevs = sorted(bheadset) | |
474 | self[branch] = [cl.node(rev) for rev in bheadrevs] |
|
523 | self[branch] = [cl.node(rev) for rev in bheadrevs] | |
475 | tiprev = bheadrevs[-1] |
|
524 | tiprev = bheadrevs[-1] |
@@ -39,6 +39,10 b'' | |||||
39 |
|
39 | |||
40 | * External hooks are now called with `HGPLAIN=1` preset. |
|
40 | * External hooks are now called with `HGPLAIN=1` preset. | |
41 |
|
41 | |||
|
42 | * The `branchmap` cache is updated more intelligently and can be | |||
|
43 | significantly faster for repositories with many branches and changesets. | |||
|
44 | ||||
|
45 | ||||
42 | == New Experimental Features == |
|
46 | == New Experimental Features == | |
43 |
|
47 | |||
44 | * `experimental.single-head-per-branch:public-changes-only` can be used |
|
48 | * `experimental.single-head-per-branch:public-changes-only` can be used |
@@ -988,3 +988,257 b' Test --force-close-branch to close a bra' | |||||
988 |
|
988 | |||
989 | $ hg ci -m "branch closed" --force-close-branch |
|
989 | $ hg ci -m "branch closed" --force-close-branch | |
990 | created new head |
|
990 | created new head | |
|
991 | $ cd .. | |||
|
992 | ||||
|
993 | Test various special cases for the branchmap | |||
|
994 | -------------------------------------------- | |||
|
995 | ||||
|
996 | Basic fork of the same branch | |||
|
997 | ||||
|
998 | $ hg init branchmap-testing1 | |||
|
999 | $ cd branchmap-testing1 | |||
|
1000 | $ hg debugbuild '@A . :base . :p1 *base /p1' | |||
|
1001 | $ hg log -G | |||
|
1002 | o changeset: 3:71ca9a6d524e | |||
|
1003 | |\ branch: A | |||
|
1004 | | | tag: tip | |||
|
1005 | | | parent: 2:a3b807b3ff0b | |||
|
1006 | | | parent: 1:99ba08759bc7 | |||
|
1007 | | | user: debugbuilddag | |||
|
1008 | | | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
1009 | | | summary: r3 | |||
|
1010 | | | | |||
|
1011 | | o changeset: 2:a3b807b3ff0b | |||
|
1012 | | | branch: A | |||
|
1013 | | | parent: 0:2ab8003a1750 | |||
|
1014 | | | user: debugbuilddag | |||
|
1015 | | | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
1016 | | | summary: r2 | |||
|
1017 | | | | |||
|
1018 | o | changeset: 1:99ba08759bc7 | |||
|
1019 | |/ branch: A | |||
|
1020 | | tag: p1 | |||
|
1021 | | user: debugbuilddag | |||
|
1022 | | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
1023 | | summary: r1 | |||
|
1024 | | | |||
|
1025 | o changeset: 0:2ab8003a1750 | |||
|
1026 | branch: A | |||
|
1027 | tag: base | |||
|
1028 | user: debugbuilddag | |||
|
1029 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
1030 | summary: r0 | |||
|
1031 | ||||
|
1032 | $ hg branches | |||
|
1033 | A 3:71ca9a6d524e | |||
|
1034 | $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone | |||
|
1035 | adding changesets | |||
|
1036 | adding manifests | |||
|
1037 | adding file changes | |||
|
1038 | added 3 changesets with 0 changes to 0 files (+1 heads) | |||
|
1039 | new changesets 2ab8003a1750:a3b807b3ff0b | |||
|
1040 | updating to branch A | |||
|
1041 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
1042 | $ cd ../branchmap-testing1-clone | |||
|
1043 | $ hg pull ../branchmap-testing1 | |||
|
1044 | pulling from ../branchmap-testing1 | |||
|
1045 | searching for changes | |||
|
1046 | adding changesets | |||
|
1047 | adding manifests | |||
|
1048 | adding file changes | |||
|
1049 | added 1 changesets with 0 changes to 0 files (-1 heads) | |||
|
1050 | new changesets 71ca9a6d524e | |||
|
1051 | (run 'hg update' to get a working copy) | |||
|
1052 | $ hg branches | |||
|
1053 | A 3:71ca9a6d524e | |||
|
1054 | $ cd .. | |||
|
1055 | ||||
|
1056 | Switching to a different branch and back | |||
|
1057 | ||||
|
1058 | $ hg init branchmap-testing2 | |||
|
1059 | $ cd branchmap-testing2 | |||
|
1060 | $ hg debugbuild '@A . @B . @A .' | |||
|
1061 | $ hg log -G | |||
|
1062 | o changeset: 2:9699e9f260b5 | |||
|
1063 | | branch: A | |||
|
1064 | | tag: tip | |||
|
1065 | | user: debugbuilddag | |||
|
1066 | | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
1067 | | summary: r2 | |||
|
1068 | | | |||
|
1069 | o changeset: 1:0bc7d348d965 | |||
|
1070 | | branch: B | |||
|
1071 | | user: debugbuilddag | |||
|
1072 | | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
1073 | | summary: r1 | |||
|
1074 | | | |||
|
1075 | o changeset: 0:2ab8003a1750 | |||
|
1076 | branch: A | |||
|
1077 | user: debugbuilddag | |||
|
1078 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
1079 | summary: r0 | |||
|
1080 | ||||
|
1081 | $ hg branches | |||
|
1082 | A 2:9699e9f260b5 | |||
|
1083 | B 1:0bc7d348d965 (inactive) | |||
|
1084 | $ hg clone -r 1 . ../branchmap-testing2-clone | |||
|
1085 | adding changesets | |||
|
1086 | adding manifests | |||
|
1087 | adding file changes | |||
|
1088 | added 2 changesets with 0 changes to 0 files | |||
|
1089 | new changesets 2ab8003a1750:0bc7d348d965 | |||
|
1090 | updating to branch B | |||
|
1091 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
1092 | $ cd ../branchmap-testing2-clone | |||
|
1093 | $ hg pull ../branchmap-testing2 | |||
|
1094 | pulling from ../branchmap-testing2 | |||
|
1095 | searching for changes | |||
|
1096 | adding changesets | |||
|
1097 | adding manifests | |||
|
1098 | adding file changes | |||
|
1099 | added 1 changesets with 0 changes to 0 files | |||
|
1100 | new changesets 9699e9f260b5 | |||
|
1101 | (run 'hg update' to get a working copy) | |||
|
1102 | $ hg branches | |||
|
1103 | A 2:9699e9f260b5 | |||
|
1104 | B 1:0bc7d348d965 (inactive) | |||
|
1105 | $ cd .. | |||
|
1106 | ||||
|
1107 | A fork on a branch switching to a different branch and back | |||
|
1108 | is still collecting the fork. | |||
|
1109 | ||||
|
1110 | $ hg init branchmap-testing3 | |||
|
1111 | $ cd branchmap-testing3 | |||
|
1112 | $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1' | |||
|
1113 | $ hg log -G | |||
|
1114 | o changeset: 4:3614a1711d23 | |||
|
1115 | |\ branch: A | |||
|
1116 | | | tag: tip | |||
|
1117 | | | parent: 3:e9c8abcf65aa | |||
|
1118 | | | parent: 1:99ba08759bc7 | |||
|
1119 | | | user: debugbuilddag | |||
|
1120 | | | date: Thu Jan 01 00:00:04 1970 +0000 | |||
|
1121 | | | summary: r4 | |||
|
1122 | | | | |||
|
1123 | | o changeset: 3:e9c8abcf65aa | |||
|
1124 | | | branch: B | |||
|
1125 | | | user: debugbuilddag | |||
|
1126 | | | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
1127 | | | summary: r3 | |||
|
1128 | | | | |||
|
1129 | | o changeset: 2:a3b807b3ff0b | |||
|
1130 | | | branch: A | |||
|
1131 | | | parent: 0:2ab8003a1750 | |||
|
1132 | | | user: debugbuilddag | |||
|
1133 | | | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
1134 | | | summary: r2 | |||
|
1135 | | | | |||
|
1136 | o | changeset: 1:99ba08759bc7 | |||
|
1137 | |/ branch: A | |||
|
1138 | | tag: p1 | |||
|
1139 | | user: debugbuilddag | |||
|
1140 | | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
1141 | | summary: r1 | |||
|
1142 | | | |||
|
1143 | o changeset: 0:2ab8003a1750 | |||
|
1144 | branch: A | |||
|
1145 | tag: base | |||
|
1146 | user: debugbuilddag | |||
|
1147 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
1148 | summary: r0 | |||
|
1149 | ||||
|
1150 | $ hg branches | |||
|
1151 | A 4:3614a1711d23 | |||
|
1152 | B 3:e9c8abcf65aa (inactive) | |||
|
1153 | $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone | |||
|
1154 | adding changesets | |||
|
1155 | adding manifests | |||
|
1156 | adding file changes | |||
|
1157 | added 4 changesets with 0 changes to 0 files (+1 heads) | |||
|
1158 | new changesets 2ab8003a1750:e9c8abcf65aa | |||
|
1159 | updating to branch A | |||
|
1160 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
1161 | $ cd ../branchmap-testing3-clone | |||
|
1162 | $ hg pull ../branchmap-testing3 | |||
|
1163 | pulling from ../branchmap-testing3 | |||
|
1164 | searching for changes | |||
|
1165 | adding changesets | |||
|
1166 | adding manifests | |||
|
1167 | adding file changes | |||
|
1168 | added 1 changesets with 0 changes to 0 files (-1 heads) | |||
|
1169 | new changesets 3614a1711d23 | |||
|
1170 | (run 'hg update' to get a working copy) | |||
|
1171 | $ hg branches | |||
|
1172 | A 4:3614a1711d23 | |||
|
1173 | B 3:e9c8abcf65aa (inactive) | |||
|
1174 | $ cd .. | |||
|
1175 | ||||
|
1176 | Intermediary parents are on different branches. | |||
|
1177 | ||||
|
1178 | $ hg init branchmap-testing4 | |||
|
1179 | $ cd branchmap-testing4 | |||
|
1180 | $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1' | |||
|
1181 | $ hg log -G | |||
|
1182 | o changeset: 4:4bf67499b70a | |||
|
1183 | |\ branch: A | |||
|
1184 | | | tag: tip | |||
|
1185 | | | parent: 3:4a546028fa8f | |||
|
1186 | | | parent: 1:0bc7d348d965 | |||
|
1187 | | | user: debugbuilddag | |||
|
1188 | | | date: Thu Jan 01 00:00:04 1970 +0000 | |||
|
1189 | | | summary: r4 | |||
|
1190 | | | | |||
|
1191 | | o changeset: 3:4a546028fa8f | |||
|
1192 | | | branch: C | |||
|
1193 | | | user: debugbuilddag | |||
|
1194 | | | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
1195 | | | summary: r3 | |||
|
1196 | | | | |||
|
1197 | | o changeset: 2:a3b807b3ff0b | |||
|
1198 | | | branch: A | |||
|
1199 | | | parent: 0:2ab8003a1750 | |||
|
1200 | | | user: debugbuilddag | |||
|
1201 | | | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
1202 | | | summary: r2 | |||
|
1203 | | | | |||
|
1204 | o | changeset: 1:0bc7d348d965 | |||
|
1205 | |/ branch: B | |||
|
1206 | | tag: p1 | |||
|
1207 | | user: debugbuilddag | |||
|
1208 | | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
1209 | | summary: r1 | |||
|
1210 | | | |||
|
1211 | o changeset: 0:2ab8003a1750 | |||
|
1212 | branch: A | |||
|
1213 | tag: base | |||
|
1214 | user: debugbuilddag | |||
|
1215 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
1216 | summary: r0 | |||
|
1217 | ||||
|
1218 | $ hg branches | |||
|
1219 | A 4:4bf67499b70a | |||
|
1220 | C 3:4a546028fa8f (inactive) | |||
|
1221 | B 1:0bc7d348d965 (inactive) | |||
|
1222 | $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone | |||
|
1223 | adding changesets | |||
|
1224 | adding manifests | |||
|
1225 | adding file changes | |||
|
1226 | added 4 changesets with 0 changes to 0 files (+1 heads) | |||
|
1227 | new changesets 2ab8003a1750:4a546028fa8f | |||
|
1228 | updating to branch B | |||
|
1229 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
1230 | $ cd ../branchmap-testing4-clone | |||
|
1231 | $ hg pull ../branchmap-testing4 | |||
|
1232 | pulling from ../branchmap-testing4 | |||
|
1233 | searching for changes | |||
|
1234 | adding changesets | |||
|
1235 | adding manifests | |||
|
1236 | adding file changes | |||
|
1237 | added 1 changesets with 0 changes to 0 files (-1 heads) | |||
|
1238 | new changesets 4bf67499b70a | |||
|
1239 | (run 'hg update' to get a working copy) | |||
|
1240 | $ hg branches | |||
|
1241 | A 4:4bf67499b70a | |||
|
1242 | C 3:4a546028fa8f (inactive) | |||
|
1243 | B 1:0bc7d348d965 (inactive) | |||
|
1244 | $ cd .. |
General Comments 0
You need to be logged in to leave comments.
Login now