Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 3153: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
3152:15d585dcdd1c | 3153: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 |