comparison mercurial/merge.py @ 3155:c82ea81d6850

Add core copy detection algorithm This adds findcopies, which detects merge-relevant copies between files in a pair of manifests back to the merge ancestor. While the merge code invokes the copy detection routine, it does not yet use the result.
author Matt Mackall <mpm@selenic.com>
date Mon, 25 Sep 2006 16:45:31 -0500
parents 2ef0b3aae186
children 56c59ba7aa76
comparison
equal deleted inserted replaced
3154:15d585dcdd1c 3155:c82ea81d6850
91 for f in deleted + removed: 91 for f in deleted + removed:
92 if f not in m2: 92 if f not in m2:
93 action.append((f, "f")) 93 action.append((f, "f"))
94 94
95 return action 95 return action
96
97 def nonoverlap(d1, d2):
98 """
99 Return list of elements in d1 not in d2
100 """
101
102 l = []
103 for d in d1:
104 if d not in d2:
105 l.append(d)
106
107 l.sort()
108 return l
109
110 def findold(fctx, limit):
111 """
112 find files that path was copied from, back to linkrev limit
113 """
114
115 old = {}
116 orig = fctx.path()
117 visit = [fctx]
118 while visit:
119 fc = visit.pop()
120 if fc.rev() < limit:
121 continue
122 if fc.path() != orig and fc.path() not in old:
123 old[fc.path()] = 1
124 visit += fc.parents()
125
126 old = old.keys()
127 old.sort()
128 return old
129
130 def findcopies(repo, m1, m2, limit):
131 """
132 Find moves and copies between m1 and m2 back to limit linkrev
133 """
134
135 copy = {}
136 match = {}
137 u1 = nonoverlap(m1, m2)
138 u2 = nonoverlap(m2, m1)
139 ctx = util.cachefunc(lambda f,n: repo.filectx(f, fileid=n[:20]))
140
141 def checkpair(c, f2, man):
142 ''' check if an apparent pair actually matches '''
143 c2 = ctx(f2, man[f2])
144 ca = c.ancestor(c2)
145 if ca:
146 copy[c.path()] = f2
147 copy[f2] = c.path()
148
149 for f in u1:
150 c = ctx(f, m1[f])
151 for of in findold(c, limit):
152 if of in m2:
153 checkpair(c, of, m2)
154 else:
155 match.setdefault(of, []).append(f)
156
157 for f in u2:
158 c = ctx(f, m2[f])
159 for of in findold(c, limit):
160 if of in m1:
161 checkpair(c, of, m1)
162 elif of in match:
163 for mf in match[of]:
164 checkpair(c, mf, m1)
165
166 return copy
96 167
97 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial): 168 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
98 """ 169 """
99 Merge manifest m1 with m2 using ancestor ma and generate merge action list 170 Merge manifest m1 with m2 using ancestor ma and generate merge action list
100 """ 171 """
287 358
288 if not force: 359 if not force:
289 checkunknown(repo, m2, status) 360 checkunknown(repo, m2, status)
290 if not branchmerge: 361 if not branchmerge:
291 action += forgetremoved(m2, status) 362 action += forgetremoved(m2, status)
363
364 copy = {}
365 if not (backwards or overwrite):
366 copy = findcopies(repo, m1, m2, repo.changelog.rev(pa))
367
292 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial) 368 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
293 del m1, m2, ma 369 del m1, m2, ma
294 370
295 ### apply phase 371 ### apply phase
296 372