##// 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 return None
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 class workingctx(changectx):
509 class workingctx(changectx):
499 """A workingctx object makes access to data related to
510 """A workingctx object makes access to data related to
500 the current working directory convenient.
511 the current working directory convenient.
@@ -28,27 +28,6 b' def _dirs(files):'
28 f = _dirname(f)
28 f = _dirname(f)
29 return d
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 def _findlimit(repo, a, b):
31 def _findlimit(repo, a, b):
53 """Find the earliest revision that's an ancestor of a or b but not both,
32 """Find the earliest revision that's an ancestor of a or b but not both,
54 None if no such revision exists.
33 None if no such revision exists.
@@ -138,22 +117,49 b' def copies(repo, c1, c2, ca, checkdirs=F'
138 fullcopy = {}
117 fullcopy = {}
139 diverge = {}
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 def checkcopies(f, m1, m2):
136 def checkcopies(f, m1, m2):
142 '''check possible copies of f from m1 to m2'''
137 '''check possible copies of f from m1 to m2'''
143 c1 = ctx(f, m1[f])
138 of = None
144 for of in _findoldnames(c1, limit):
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 fullcopy[f] = of # remember for dir rename detection
150 fullcopy[f] = of # remember for dir rename detection
146 if of in m2: # original file not in other manifest?
151 if of not in m2:
147 # if the original file is unchanged on the other branch,
152 continue # no match, keep looking
148 # no merge needed
153 if m2[of] == ma.get(of):
149 if m2[of] != ma.get(of):
154 break # no merge needed, quit early
150 c2 = ctx(of, m2[of])
155 c2 = ctx(of, m2[of])
151 ca = c1.ancestor(c2)
156 cr = related(oc, c2, ca.rev())
152 # related and named changed on only one side?
157 if of == f or of == c2.path(): # non-divergent
153 if ca and (ca.path() == f or ca.path() == c2.path()):
154 if c1 != ca or c2 != ca: # merge needed?
155 copy[f] = of
158 copy[f] = of
156 elif of in ma:
159 of = None
160 break
161
162 if of in ma:
157 diverge.setdefault(of, []).append(f)
163 diverge.setdefault(of, []).append(f)
158
164
159 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
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