148 t[k] = t[v] |
148 t[k] = t[v] |
149 else: |
149 else: |
150 t[k] = v |
150 t[k] = v |
151 return t |
151 return t |
152 |
152 |
153 def _tracefile(fctx, am, limit): |
153 def _tracefile(fctx, am, basemf, limit): |
154 """return file context that is the ancestor of fctx present in ancestor |
154 """return file context that is the ancestor of fctx present in ancestor |
155 manifest am, stopping after the first ancestor lower than limit""" |
155 manifest am, stopping after the first ancestor lower than limit""" |
156 |
156 |
157 for f in fctx.ancestors(): |
157 for f in fctx.ancestors(): |
158 path = f.path() |
158 path = f.path() |
159 if am.get(path, None) == f.filenode(): |
159 if am.get(path, None) == f.filenode(): |
|
160 return path |
|
161 if basemf and basemf.get(path, None) == f.filenode(): |
160 return path |
162 return path |
161 if not f.isintroducedafter(limit): |
163 if not f.isintroducedafter(limit): |
162 return None |
164 return None |
163 |
165 |
164 def _dirstatecopies(repo, match=None): |
166 def _dirstatecopies(repo, match=None): |
181 def usechangesetcentricalgo(repo): |
183 def usechangesetcentricalgo(repo): |
182 """Checks if we should use changeset-centric copy algorithms""" |
184 """Checks if we should use changeset-centric copy algorithms""" |
183 return (repo.ui.config('experimental', 'copies.read-from') in |
185 return (repo.ui.config('experimental', 'copies.read-from') in |
184 ('changeset-only', 'compatibility')) |
186 ('changeset-only', 'compatibility')) |
185 |
187 |
186 def _committedforwardcopies(a, b, match): |
188 def _committedforwardcopies(a, b, base, match): |
187 """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" |
189 """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" |
188 # files might have to be traced back to the fctx parent of the last |
190 # files might have to be traced back to the fctx parent of the last |
189 # one-side-only changeset, but not further back than that |
191 # one-side-only changeset, but not further back than that |
190 repo = a._repo |
192 repo = a._repo |
191 |
193 |
199 % (a, b)) |
201 % (a, b)) |
200 limit = _findlimit(repo, a, b) |
202 limit = _findlimit(repo, a, b) |
201 if debug: |
203 if debug: |
202 dbg('debug.copies: search limit: %d\n' % limit) |
204 dbg('debug.copies: search limit: %d\n' % limit) |
203 am = a.manifest() |
205 am = a.manifest() |
|
206 basemf = None if base is None else base.manifest() |
204 |
207 |
205 # find where new files came from |
208 # find where new files came from |
206 # we currently don't try to find where old files went, too expensive |
209 # we currently don't try to find where old files went, too expensive |
207 # this means we can miss a case like 'hg rm b; hg cp a b' |
210 # this means we can miss a case like 'hg rm b; hg cp a b' |
208 cm = {} |
211 cm = {} |
309 if f in newcopies: |
312 if f in newcopies: |
310 del newcopies[f] |
313 del newcopies[f] |
311 heapq.heappush(work, (c, parent, newcopies)) |
314 heapq.heappush(work, (c, parent, newcopies)) |
312 assert False |
315 assert False |
313 |
316 |
314 def _forwardcopies(a, b, match=None): |
317 def _forwardcopies(a, b, base=None, match=None): |
315 """find {dst@b: src@a} copy mapping where a is an ancestor of b""" |
318 """find {dst@b: src@a} copy mapping where a is an ancestor of b""" |
316 |
319 |
|
320 if base is None: |
|
321 base = a |
317 match = a.repo().narrowmatch(match) |
322 match = a.repo().narrowmatch(match) |
318 # check for working copy |
323 # check for working copy |
319 if b.rev() is None: |
324 if b.rev() is None: |
320 cm = _committedforwardcopies(a, b.p1(), match) |
325 cm = _committedforwardcopies(a, b.p1(), base, match) |
321 # combine copies from dirstate if necessary |
326 # combine copies from dirstate if necessary |
322 copies = _chain(cm, _dirstatecopies(b._repo, match)) |
327 copies = _chain(cm, _dirstatecopies(b._repo, match)) |
323 else: |
328 else: |
324 copies = _committedforwardcopies(a, b, match) |
329 copies = _committedforwardcopies(a, b, base, match) |
325 return copies |
330 return copies |
326 |
331 |
327 def _backwardrenames(a, b, match): |
332 def _backwardrenames(a, b, match): |
328 if a._repo.ui.config('experimental', 'copytrace') == 'off': |
333 if a._repo.ui.config('experimental', 'copytrace') == 'off': |
329 return {} |
334 return {} |
367 repo.ui.debug('debug.copies: search mode: backward\n') |
372 repo.ui.debug('debug.copies: search mode: backward\n') |
368 copies = _backwardrenames(x, y, match=match) |
373 copies = _backwardrenames(x, y, match=match) |
369 else: |
374 else: |
370 if debug: |
375 if debug: |
371 repo.ui.debug('debug.copies: search mode: combined\n') |
376 repo.ui.debug('debug.copies: search mode: combined\n') |
|
377 base = None |
|
378 if a.rev() != node.nullrev: |
|
379 base = x |
372 copies = _chain(_backwardrenames(x, a, match=match), |
380 copies = _chain(_backwardrenames(x, a, match=match), |
373 _forwardcopies(a, y, match=match)) |
381 _forwardcopies(a, y, base, match=match)) |
374 _filter(x, y, copies) |
382 _filter(x, y, copies) |
375 return copies |
383 return copies |
376 |
384 |
377 def mergecopies(repo, c1, c2, base): |
385 def mergecopies(repo, c1, c2, base): |
378 """ |
386 """ |