mercurial/copies.py
changeset 44199 7f8bdee0034e
parent 44197 17e12938f8e7
child 44200 fa9ad1da2e77
equal deleted inserted replaced
44198:8ad263c3a358 44199:7f8bdee0034e
   450     revision 4, and if user have copytrace disabled, we prints the following
   450     revision 4, and if user have copytrace disabled, we prints the following
   451     message:
   451     message:
   452 
   452 
   453     ```other changed <file> which local deleted```
   453     ```other changed <file> which local deleted```
   454 
   454 
   455     Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
   455     Returns a tuple where:
   456     "dirmove".
   456 
   457 
   457     "branch_copies" an instance of branch_copies.
   458     "copy" is a mapping from destination name -> source name,
       
   459     where source is in c1 and destination is in c2 or vice-versa.
       
   460 
       
   461     "movewithdir" is a mapping from source name -> destination name,
       
   462     where the file at source present in one context but not the other
       
   463     needs to be moved to destination by the merge process, because the
       
   464     other context moved the directory it is in.
       
   465 
   458 
   466     "diverge" is a mapping of source name -> list of destination names
   459     "diverge" is a mapping of source name -> list of destination names
   467     for divergent renames.
   460     for divergent renames.
   468 
   461 
   469     "renamedelete" is a mapping of source name -> list of destination
       
   470     names for files deleted in c1 that were renamed in c2 or vice-versa.
       
   471 
       
   472     "dirmove" is a mapping of detected source dir -> destination dir renames.
       
   473     This is needed for handling changes to new files previously grafted into
       
   474     renamed directories.
       
   475 
       
   476     This function calls different copytracing algorithms based on config.
   462     This function calls different copytracing algorithms based on config.
   477     """
   463     """
   478     # avoid silly behavior for update from empty dir
   464     # avoid silly behavior for update from empty dir
   479     if not c1 or not c2 or c1 == c2:
   465     if not c1 or not c2 or c1 == c2:
   480         return {}, {}, {}, {}, {}
   466         return branch_copies(), {}
   481 
   467 
   482     narrowmatch = c1.repo().narrowmatch()
   468     narrowmatch = c1.repo().narrowmatch()
   483 
   469 
   484     # avoid silly behavior for parent -> working dir
   470     # avoid silly behavior for parent -> working dir
   485     if c2.node() is None and c1.node() == repo.dirstate.p1():
   471     if c2.node() is None and c1.node() == repo.dirstate.p1():
   486         return _dirstatecopies(repo, narrowmatch), {}, {}, {}, {}
   472         return branch_copies(_dirstatecopies(repo, narrowmatch)), {}
   487 
   473 
   488     copytracing = repo.ui.config(b'experimental', b'copytrace')
   474     copytracing = repo.ui.config(b'experimental', b'copytrace')
   489     if stringutil.parsebool(copytracing) is False:
   475     if stringutil.parsebool(copytracing) is False:
   490         # stringutil.parsebool() returns None when it is unable to parse the
   476         # stringutil.parsebool() returns None when it is unable to parse the
   491         # value, so we should rely on making sure copytracing is on such cases
   477         # value, so we should rely on making sure copytracing is on such cases
   492         return {}, {}, {}, {}, {}
   478         return branch_copies(), {}
   493 
   479 
   494     if usechangesetcentricalgo(repo):
   480     if usechangesetcentricalgo(repo):
   495         # The heuristics don't make sense when we need changeset-centric algos
   481         # The heuristics don't make sense when we need changeset-centric algos
   496         return _fullcopytracing(repo, c1, c2, base)
   482         return _fullcopytracing(repo, c1, c2, base)
   497 
   483 
   546                 # dst not added on side 2 (handle as regular
   532                 # dst not added on side 2 (handle as regular
   547                 # "both created" case in manifestmerge otherwise)
   533                 # "both created" case in manifestmerge otherwise)
   548                 copy[dst] = src
   534                 copy[dst] = src
   549 
   535 
   550 
   536 
       
   537 class branch_copies(object):
       
   538     """Information about copies made on one side of a merge/graft.
       
   539 
       
   540     "copy" is a mapping from destination name -> source name,
       
   541     where source is in c1 and destination is in c2 or vice-versa.
       
   542 
       
   543     "movewithdir" is a mapping from source name -> destination name,
       
   544     where the file at source present in one context but not the other
       
   545     needs to be moved to destination by the merge process, because the
       
   546     other context moved the directory it is in.
       
   547 
       
   548     "renamedelete" is a mapping of source name -> list of destination
       
   549     names for files deleted in c1 that were renamed in c2 or vice-versa.
       
   550 
       
   551     "dirmove" is a mapping of detected source dir -> destination dir renames.
       
   552     This is needed for handling changes to new files previously grafted into
       
   553     renamed directories.
       
   554     """
       
   555 
       
   556     def __init__(
       
   557         self, copy=None, renamedelete=None, dirmove=None, movewithdir=None
       
   558     ):
       
   559         self.copy = {} if copy is None else copy
       
   560         self.renamedelete = {} if renamedelete is None else renamedelete
       
   561         self.dirmove = {} if dirmove is None else dirmove
       
   562         self.movewithdir = {} if movewithdir is None else movewithdir
       
   563 
       
   564 
   551 def _fullcopytracing(repo, c1, c2, base):
   565 def _fullcopytracing(repo, c1, c2, base):
   552     """ The full copytracing algorithm which finds all the new files that were
   566     """ The full copytracing algorithm which finds all the new files that were
   553     added from merge base up to the top commit and for each file it checks if
   567     added from merge base up to the top commit and for each file it checks if
   554     this file was copied from another file.
   568     this file was copied from another file.
   555 
   569 
   562 
   576 
   563     copies1 = pathcopies(base, c1)
   577     copies1 = pathcopies(base, c1)
   564     copies2 = pathcopies(base, c2)
   578     copies2 = pathcopies(base, c2)
   565 
   579 
   566     if not (copies1 or copies2):
   580     if not (copies1 or copies2):
   567         return {}, {}, {}, {}, {}
   581         return branch_copies(), {}
   568 
   582 
   569     inversecopies1 = {}
   583     inversecopies1 = {}
   570     inversecopies2 = {}
   584     inversecopies2 = {}
   571     for dst, src in copies1.items():
   585     for dst, src in copies1.items():
   572         inversecopies1.setdefault(src, []).append(dst)
   586         inversecopies1.setdefault(src, []).append(dst)
   670     copy1.update(copy2)
   684     copy1.update(copy2)
   671     renamedelete1.update(renamedelete2)
   685     renamedelete1.update(renamedelete2)
   672     movewithdir1.update(movewithdir2)
   686     movewithdir1.update(movewithdir2)
   673     dirmove1.update(dirmove2)
   687     dirmove1.update(dirmove2)
   674 
   688 
   675     return copy1, movewithdir1, diverge, renamedelete1, dirmove1
   689     return branch_copies(copy1, renamedelete1, dirmove1, movewithdir1), diverge
   676 
   690 
   677 
   691 
   678 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
   692 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
   679     """Finds moved directories and files that should move with them.
   693     """Finds moved directories and files that should move with them.
   680 
   694 
   844                     # if there are a few related copies then we'll merge
   858                     # if there are a few related copies then we'll merge
   845                     # changes into all of them. This matches the behaviour
   859                     # changes into all of them. This matches the behaviour
   846                     # of upstream copytracing
   860                     # of upstream copytracing
   847                     copies[candidate] = f
   861                     copies[candidate] = f
   848 
   862 
   849     return copies, {}, {}, {}, {}
   863     return branch_copies(copies), {}
   850 
   864 
   851 
   865 
   852 def _related(f1, f2):
   866 def _related(f1, f2):
   853     """return True if f1 and f2 filectx have a common ancestor
   867     """return True if f1 and f2 filectx have a common ancestor
   854 
   868