##// END OF EJS Templates
branchmap: avoid ancestor computations in absence of non-continous branches...
Joerg Sonnenberger -
r46880:c4b792fa default
parent child Browse files
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 # assert not (set(bheadrevs) & set(newheadrevs))
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 floorrev = min(uncertain)
516 if topoheads is None:
471 ancestors = set(cl.ancestors(newheadrevs, floorrev))
517 topoheads = set(cl.headrevs())
472 bheadset -= ancestors
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