##// END OF EJS Templates
copies: speed up copy detection...
Matt Mackall -
r10262:eb243551 stable
parent child Browse files
Show More
@@ -495,6 +495,17 b' class filectx(object):'
495 495
496 496 return None
497 497
498 def ancestors(self):
499 seen = set(str(self))
500 visit = [self]
501 while visit:
502 for parent in visit.pop(0).parents():
503 s = str(parent)
504 if s not in seen:
505 visit.append(parent)
506 seen.add(s)
507 yield parent
508
498 509 class workingctx(changectx):
499 510 """A workingctx object makes access to data related to
500 511 the current working directory convenient.
@@ -28,27 +28,6 b' def _dirs(files):'
28 28 f = _dirname(f)
29 29 return d
30 30
31 def _findoldnames(fctx, limit):
32 "find files that path was copied from, back to linkrev limit"
33 old = {}
34 seen = set()
35 orig = fctx.path()
36 visit = [(fctx, 0)]
37 while visit:
38 fc, depth = visit.pop()
39 s = str(fc)
40 if s in seen:
41 continue
42 seen.add(s)
43 if fc.path() != orig and fc.path() not in old:
44 old[fc.path()] = (depth, fc.path()) # remember depth
45 if fc.rev() is not None and fc.rev() < limit:
46 continue
47 visit += [(p, depth - 1) for p in fc.parents()]
48
49 # return old names sorted by depth
50 return [o[1] for o in sorted(old.values())]
51
52 31 def _findlimit(repo, a, b):
53 32 """Find the earliest revision that's an ancestor of a or b but not both,
54 33 None if no such revision exists.
@@ -138,22 +117,49 b' def copies(repo, c1, c2, ca, checkdirs=F'
138 117 fullcopy = {}
139 118 diverge = {}
140 119
120 def related(f1, f2, limit):
121 g1, g2 = f1.ancestors(), f2.ancestors()
122 try:
123 while 1:
124 f1r, f2r = f1.rev(), f2.rev()
125 if f1r > f2r:
126 f1 = g1.next()
127 elif f2r > f1r:
128 f2 = g2.next()
129 elif f1 == f2:
130 return f1 # a match
131 elif f1r == f2r or f1r < limit or f2r < limit:
132 return False # copy no longer relevant
133 except StopIteration:
134 return False
135
141 136 def checkcopies(f, m1, m2):
142 137 '''check possible copies of f from m1 to m2'''
143 c1 = ctx(f, m1[f])
144 for of in _findoldnames(c1, limit):
138 of = None
139 seen = set([f])
140 for oc in ctx(f, m1[f]).ancestors():
141 ocr = oc.rev()
142 of = oc.path()
143 if of in seen:
144 # check limit late - grab last rename before
145 if ocr < limit:
146 break
147 continue
148 seen.add(of)
149
145 150 fullcopy[f] = of # remember for dir rename detection
146 if of in m2: # original file not in other manifest?
147 # if the original file is unchanged on the other branch,
148 # no merge needed
149 if m2[of] != ma.get(of):
151 if of not in m2:
152 continue # no match, keep looking
153 if m2[of] == ma.get(of):
154 break # no merge needed, quit early
150 155 c2 = ctx(of, m2[of])
151 ca = c1.ancestor(c2)
152 # related and named changed on only one side?
153 if ca and (ca.path() == f or ca.path() == c2.path()):
154 if c1 != ca or c2 != ca: # merge needed?
156 cr = related(oc, c2, ca.rev())
157 if of == f or of == c2.path(): # non-divergent
155 158 copy[f] = of
156 elif of in ma:
159 of = None
160 break
161
162 if of in ma:
157 163 diverge.setdefault(of, []).append(f)
158 164
159 165 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
General Comments 0
You need to be logged in to leave comments. Login now