308 def mergecopies(repo, c1, c2, base): |
308 def mergecopies(repo, c1, c2, base): |
309 """ |
309 """ |
310 Find moves and copies between context c1 and c2 that are relevant |
310 Find moves and copies between context c1 and c2 that are relevant |
311 for merging. 'base' will be used as the merge base. |
311 for merging. 'base' will be used as the merge base. |
312 |
312 |
313 Returns four dicts: "copy", "movewithdir", "diverge", and |
313 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and |
314 "renamedelete". |
314 "dirmove". |
315 |
315 |
316 "copy" is a mapping from destination name -> source name, |
316 "copy" is a mapping from destination name -> source name, |
317 where source is in c1 and destination is in c2 or vice-versa. |
317 where source is in c1 and destination is in c2 or vice-versa. |
318 |
318 |
319 "movewithdir" is a mapping from source name -> destination name, |
319 "movewithdir" is a mapping from source name -> destination name, |
324 "diverge" is a mapping of source name -> list of destination names |
324 "diverge" is a mapping of source name -> list of destination names |
325 for divergent renames. |
325 for divergent renames. |
326 |
326 |
327 "renamedelete" is a mapping of source name -> list of destination |
327 "renamedelete" is a mapping of source name -> list of destination |
328 names for files deleted in c1 that were renamed in c2 or vice-versa. |
328 names for files deleted in c1 that were renamed in c2 or vice-versa. |
|
329 |
|
330 "dirmove" is a mapping of detected source dir -> destination dir renames. |
|
331 This is needed for handling changes to new files previously grafted into |
|
332 renamed directories. |
329 """ |
333 """ |
330 # avoid silly behavior for update from empty dir |
334 # avoid silly behavior for update from empty dir |
331 if not c1 or not c2 or c1 == c2: |
335 if not c1 or not c2 or c1 == c2: |
332 return {}, {}, {}, {} |
336 return {}, {}, {}, {}, {} |
333 |
337 |
334 # avoid silly behavior for parent -> working dir |
338 # avoid silly behavior for parent -> working dir |
335 if c2.node() is None and c1.node() == repo.dirstate.p1(): |
339 if c2.node() is None and c1.node() == repo.dirstate.p1(): |
336 return repo.dirstate.copies(), {}, {}, {} |
340 return repo.dirstate.copies(), {}, {}, {}, {} |
337 |
341 |
338 # Copy trace disabling is explicitly below the node == p1 logic above |
342 # Copy trace disabling is explicitly below the node == p1 logic above |
339 # because the logic above is required for a simple copy to be kept across a |
343 # because the logic above is required for a simple copy to be kept across a |
340 # rebase. |
344 # rebase. |
341 if repo.ui.configbool('experimental', 'disablecopytrace'): |
345 if repo.ui.configbool('experimental', 'disablecopytrace'): |
342 return {}, {}, {}, {} |
346 return {}, {}, {}, {}, {} |
343 |
347 |
344 # In certain scenarios (e.g. graft, update or rebase), base can be |
348 # In certain scenarios (e.g. graft, update or rebase), base can be |
345 # overridden We still need to know a real common ancestor in this case We |
349 # overridden We still need to know a real common ancestor in this case We |
346 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there |
350 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there |
347 # can be multiple common ancestors, e.g. in case of bidmerge. Because our |
351 # can be multiple common ancestors, e.g. in case of bidmerge. Because our |
363 tca = _c1.ancestor(_c2) |
367 tca = _c1.ancestor(_c2) |
364 |
368 |
365 limit = _findlimit(repo, c1.rev(), c2.rev()) |
369 limit = _findlimit(repo, c1.rev(), c2.rev()) |
366 if limit is None: |
370 if limit is None: |
367 # no common ancestor, no copies |
371 # no common ancestor, no copies |
368 return {}, {}, {}, {} |
372 return {}, {}, {}, {}, {} |
369 repo.ui.debug(" searching for copies back to rev %d\n" % limit) |
373 repo.ui.debug(" searching for copies back to rev %d\n" % limit) |
370 |
374 |
371 m1 = c1.manifest() |
375 m1 = c1.manifest() |
372 m2 = c2.manifest() |
376 m2 = c2.manifest() |
373 mb = base.manifest() |
377 mb = base.manifest() |
501 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f, |
505 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f, |
502 note)) |
506 note)) |
503 del divergeset |
507 del divergeset |
504 |
508 |
505 if not fullcopy: |
509 if not fullcopy: |
506 return copy, {}, diverge, renamedelete |
510 return copy, {}, diverge, renamedelete, {} |
507 |
511 |
508 repo.ui.debug(" checking for directory renames\n") |
512 repo.ui.debug(" checking for directory renames\n") |
509 |
513 |
510 # generate a directory move map |
514 # generate a directory move map |
511 d1, d2 = c1.dirs(), c2.dirs() |
515 d1, d2 = c1.dirs(), c2.dirs() |
559 movewithdir[f] = df |
563 movewithdir[f] = df |
560 repo.ui.debug((" pending file src: '%s' -> " |
564 repo.ui.debug((" pending file src: '%s' -> " |
561 "dst: '%s'\n") % (f, df)) |
565 "dst: '%s'\n") % (f, df)) |
562 break |
566 break |
563 |
567 |
564 return copy, movewithdir, diverge, renamedelete |
568 return copy, movewithdir, diverge, renamedelete, dirmove |
565 |
569 |
566 def _related(f1, f2, limit): |
570 def _related(f1, f2, limit): |
567 """return True if f1 and f2 filectx have a common ancestor |
571 """return True if f1 and f2 filectx have a common ancestor |
568 |
572 |
569 Walk back to common ancestor to see if the two files originate |
573 Walk back to common ancestor to see if the two files originate |