mercurial/copies.py
changeset 44200 fa9ad1da2e77
parent 44199 7f8bdee0034e
child 44210 d0c3eead515a
equal deleted inserted replaced
44199:7f8bdee0034e 44200:fa9ad1da2e77
   461 
   461 
   462     This function calls different copytracing algorithms based on config.
   462     This function calls different copytracing algorithms based on config.
   463     """
   463     """
   464     # avoid silly behavior for update from empty dir
   464     # avoid silly behavior for update from empty dir
   465     if not c1 or not c2 or c1 == c2:
   465     if not c1 or not c2 or c1 == c2:
   466         return branch_copies(), {}
   466         return branch_copies(), branch_copies(), {}
   467 
   467 
   468     narrowmatch = c1.repo().narrowmatch()
   468     narrowmatch = c1.repo().narrowmatch()
   469 
   469 
   470     # avoid silly behavior for parent -> working dir
   470     # avoid silly behavior for parent -> working dir
   471     if c2.node() is None and c1.node() == repo.dirstate.p1():
   471     if c2.node() is None and c1.node() == repo.dirstate.p1():
   472         return branch_copies(_dirstatecopies(repo, narrowmatch)), {}
   472         return (
       
   473             branch_copies(_dirstatecopies(repo, narrowmatch)),
       
   474             branch_copies(),
       
   475             {},
       
   476         )
   473 
   477 
   474     copytracing = repo.ui.config(b'experimental', b'copytrace')
   478     copytracing = repo.ui.config(b'experimental', b'copytrace')
   475     if stringutil.parsebool(copytracing) is False:
   479     if stringutil.parsebool(copytracing) is False:
   476         # stringutil.parsebool() returns None when it is unable to parse the
   480         # stringutil.parsebool() returns None when it is unable to parse the
   477         # value, so we should rely on making sure copytracing is on such cases
   481         # value, so we should rely on making sure copytracing is on such cases
   478         return branch_copies(), {}
   482         return branch_copies(), branch_copies(), {}
   479 
   483 
   480     if usechangesetcentricalgo(repo):
   484     if usechangesetcentricalgo(repo):
   481         # The heuristics don't make sense when we need changeset-centric algos
   485         # The heuristics don't make sense when we need changeset-centric algos
   482         return _fullcopytracing(repo, c1, c2, base)
   486         return _fullcopytracing(repo, c1, c2, base)
   483 
   487 
   576 
   580 
   577     copies1 = pathcopies(base, c1)
   581     copies1 = pathcopies(base, c1)
   578     copies2 = pathcopies(base, c2)
   582     copies2 = pathcopies(base, c2)
   579 
   583 
   580     if not (copies1 or copies2):
   584     if not (copies1 or copies2):
   581         return branch_copies(), {}
   585         return branch_copies(), branch_copies(), {}
   582 
   586 
   583     inversecopies1 = {}
   587     inversecopies1 = {}
   584     inversecopies2 = {}
   588     inversecopies2 = {}
   585     for dst, src in copies1.items():
   589     for dst, src in copies1.items():
   586         inversecopies1.setdefault(src, []).append(dst)
   590         inversecopies1.setdefault(src, []).append(dst)
   679     repo.ui.debug(b"  checking for directory renames\n")
   683     repo.ui.debug(b"  checking for directory renames\n")
   680 
   684 
   681     dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2)
   685     dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2)
   682     dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1)
   686     dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1)
   683 
   687 
   684     copy1.update(copy2)
   688     branch_copies1 = branch_copies(copy1, renamedelete1, dirmove1, movewithdir1)
   685     renamedelete1.update(renamedelete2)
   689     branch_copies2 = branch_copies(copy2, renamedelete2, dirmove2, movewithdir2)
   686     movewithdir1.update(movewithdir2)
   690 
   687     dirmove1.update(dirmove2)
   691     return branch_copies1, branch_copies2, diverge
   688 
       
   689     return branch_copies(copy1, renamedelete1, dirmove1, movewithdir1), diverge
       
   690 
   692 
   691 
   693 
   692 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
   694 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
   693     """Finds moved directories and files that should move with them.
   695     """Finds moved directories and files that should move with them.
   694 
   696 
   782     if c1.rev() is None:
   784     if c1.rev() is None:
   783         c1 = c1.p1()
   785         c1 = c1.p1()
   784     if c2.rev() is None:
   786     if c2.rev() is None:
   785         c2 = c2.p1()
   787         c2 = c2.p1()
   786 
   788 
   787     copies = {}
       
   788 
       
   789     changedfiles = set()
   789     changedfiles = set()
   790     m1 = c1.manifest()
   790     m1 = c1.manifest()
   791     if not repo.revs(b'%d::%d', base.rev(), c2.rev()):
   791     if not repo.revs(b'%d::%d', base.rev(), c2.rev()):
   792         # If base is not in c2 branch, we switch to fullcopytracing
   792         # If base is not in c2 branch, we switch to fullcopytracing
   793         repo.ui.debug(
   793         repo.ui.debug(
   803             repo.ui.debug(b"switching to full copytracing because of merges\n")
   803             repo.ui.debug(b"switching to full copytracing because of merges\n")
   804             return _fullcopytracing(repo, c1, c2, base)
   804             return _fullcopytracing(repo, c1, c2, base)
   805         changedfiles.update(ctx.files())
   805         changedfiles.update(ctx.files())
   806         ctx = ctx.p1()
   806         ctx = ctx.p1()
   807 
   807 
       
   808     copies2 = {}
   808     cp = _forwardcopies(base, c2)
   809     cp = _forwardcopies(base, c2)
   809     for dst, src in pycompat.iteritems(cp):
   810     for dst, src in pycompat.iteritems(cp):
   810         if src in m1:
   811         if src in m1:
   811             copies[dst] = src
   812             copies2[dst] = src
   812 
   813 
   813     # file is missing if it isn't present in the destination, but is present in
   814     # file is missing if it isn't present in the destination, but is present in
   814     # the base and present in the source.
   815     # the base and present in the source.
   815     # Presence in the base is important to exclude added files, presence in the
   816     # Presence in the base is important to exclude added files, presence in the
   816     # source is important to exclude removed files.
   817     # source is important to exclude removed files.
   817     filt = lambda f: f not in m1 and f in base and f in c2
   818     filt = lambda f: f not in m1 and f in base and f in c2
   818     missingfiles = [f for f in changedfiles if filt(f)]
   819     missingfiles = [f for f in changedfiles if filt(f)]
   819 
   820 
       
   821     copies1 = {}
   820     if missingfiles:
   822     if missingfiles:
   821         basenametofilename = collections.defaultdict(list)
   823         basenametofilename = collections.defaultdict(list)
   822         dirnametofilename = collections.defaultdict(list)
   824         dirnametofilename = collections.defaultdict(list)
   823 
   825 
   824         for f in m1.filesnotin(base.manifest()):
   826         for f in m1.filesnotin(base.manifest()):
   856                 f1 = c1.filectx(candidate)
   858                 f1 = c1.filectx(candidate)
   857                 if _related(f1, f2):
   859                 if _related(f1, f2):
   858                     # if there are a few related copies then we'll merge
   860                     # if there are a few related copies then we'll merge
   859                     # changes into all of them. This matches the behaviour
   861                     # changes into all of them. This matches the behaviour
   860                     # of upstream copytracing
   862                     # of upstream copytracing
   861                     copies[candidate] = f
   863                     copies1[candidate] = f
   862 
   864 
   863     return branch_copies(copies), {}
   865     return branch_copies(copies1), branch_copies(copies2), {}
   864 
   866 
   865 
   867 
   866 def _related(f1, f2):
   868 def _related(f1, f2):
   867     """return True if f1 and f2 filectx have a common ancestor
   869     """return True if f1 and f2 filectx have a common ancestor
   868 
   870