mercurial/copies.py
changeset 44196 6ca9f45b32b0
parent 44164 45192589555c
child 44197 17e12938f8e7
equal deleted inserted replaced
44195:51c86c6167c1 44196:6ca9f45b32b0
   571     for dst, src in copies1.items():
   571     for dst, src in copies1.items():
   572         inversecopies1.setdefault(src, []).append(dst)
   572         inversecopies1.setdefault(src, []).append(dst)
   573     for dst, src in copies2.items():
   573     for dst, src in copies2.items():
   574         inversecopies2.setdefault(src, []).append(dst)
   574         inversecopies2.setdefault(src, []).append(dst)
   575 
   575 
   576     copy = {}
   576     copy1 = {}
       
   577     copy2 = {}
   577     diverge = {}
   578     diverge = {}
   578     renamedelete = {}
   579     renamedelete1 = {}
       
   580     renamedelete2 = {}
   579     allsources = set(inversecopies1) | set(inversecopies2)
   581     allsources = set(inversecopies1) | set(inversecopies2)
   580     for src in allsources:
   582     for src in allsources:
   581         dsts1 = inversecopies1.get(src)
   583         dsts1 = inversecopies1.get(src)
   582         dsts2 = inversecopies2.get(src)
   584         dsts2 = inversecopies2.get(src)
   583         if dsts1 and dsts2:
   585         if dsts1 and dsts2:
   590                 # consider it not divergent. For example, if side 1 copies 'a'
   592                 # consider it not divergent. For example, if side 1 copies 'a'
   591                 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
   593                 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
   592                 # and 'd' and deletes 'a'.
   594                 # and 'd' and deletes 'a'.
   593                 if dsts1 & dsts2:
   595                 if dsts1 & dsts2:
   594                     for dst in dsts1 & dsts2:
   596                     for dst in dsts1 & dsts2:
   595                         copy[dst] = src
   597                         copy1[dst] = src
       
   598                         copy2[dst] = src
   596                 else:
   599                 else:
   597                     diverge[src] = sorted(dsts1 | dsts2)
   600                     diverge[src] = sorted(dsts1 | dsts2)
   598             elif src in m1 and src in m2:
   601             elif src in m1 and src in m2:
   599                 # copied on both sides
   602                 # copied on both sides
   600                 dsts1 = set(dsts1)
   603                 dsts1 = set(dsts1)
   601                 dsts2 = set(dsts2)
   604                 dsts2 = set(dsts2)
   602                 for dst in dsts1 & dsts2:
   605                 for dst in dsts1 & dsts2:
   603                     copy[dst] = src
   606                     copy1[dst] = src
       
   607                     copy2[dst] = src
   604             # TODO: Handle cases where it was renamed on one side and copied
   608             # TODO: Handle cases where it was renamed on one side and copied
   605             # on the other side
   609             # on the other side
   606         elif dsts1:
   610         elif dsts1:
   607             # copied/renamed only on side 1
   611             # copied/renamed only on side 1
   608             _checksinglesidecopies(
   612             _checksinglesidecopies(
   609                 src, dsts1, m1, m2, mb, c2, base, copy, renamedelete
   613                 src, dsts1, m1, m2, mb, c2, base, copy1, renamedelete1
   610             )
   614             )
   611         elif dsts2:
   615         elif dsts2:
   612             # copied/renamed only on side 2
   616             # copied/renamed only on side 2
   613             _checksinglesidecopies(
   617             _checksinglesidecopies(
   614                 src, dsts2, m2, m1, mb, c1, base, copy, renamedelete
   618                 src, dsts2, m2, m1, mb, c1, base, copy2, renamedelete2
   615             )
   619             )
   616 
   620 
   617     # find interesting file sets from manifests
   621     # find interesting file sets from manifests
   618     addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
   622     addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
   619     addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
   623     addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
   632     if repo.ui.debugflag:
   636     if repo.ui.debugflag:
   633         renamedeleteset = set()
   637         renamedeleteset = set()
   634         divergeset = set()
   638         divergeset = set()
   635         for dsts in diverge.values():
   639         for dsts in diverge.values():
   636             divergeset.update(dsts)
   640             divergeset.update(dsts)
   637         for dsts in renamedelete.values():
   641         for dsts in renamedelete1.values():
       
   642             renamedeleteset.update(dsts)
       
   643         for dsts in renamedelete2.values():
   638             renamedeleteset.update(dsts)
   644             renamedeleteset.update(dsts)
   639 
   645 
   640         repo.ui.debug(
   646         repo.ui.debug(
   641             b"  all copies found (* = to merge, ! = divergent, "
   647             b"  all copies found (* = to merge, ! = divergent, "
   642             b"% = renamed and deleted):\n"
   648             b"% = renamed and deleted):\n"
   643         )
   649         )
   644         for f in sorted(fullcopy):
   650         for f in sorted(fullcopy):
   645             note = b""
   651             note = b""
   646             if f in copy:
   652             if f in copy1 or f in copy2:
   647                 note += b"*"
   653                 note += b"*"
   648             if f in divergeset:
   654             if f in divergeset:
   649                 note += b"!"
   655                 note += b"!"
   650             if f in renamedeleteset:
   656             if f in renamedeleteset:
   651                 note += b"%"
   657                 note += b"%"
   655         del renamedeleteset
   661         del renamedeleteset
   656         del divergeset
   662         del divergeset
   657 
   663 
   658     repo.ui.debug(b"  checking for directory renames\n")
   664     repo.ui.debug(b"  checking for directory renames\n")
   659 
   665 
   660     dirmove, movewithdir = _dir_renames(repo, c1, c2, copy, fullcopy, u1, u2)
   666     dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2)
   661 
   667     dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1)
   662     return copy, movewithdir, diverge, renamedelete, dirmove
   668 
   663 
   669     copy1.update(copy2)
   664 
   670     renamedelete1.update(renamedelete2)
   665 def _dir_renames(repo, c1, c2, copy, fullcopy, u1, u2):
   671     movewithdir1.update(movewithdir2)
       
   672     dirmove1.update(dirmove2)
       
   673 
       
   674     return copy1, movewithdir1, diverge, renamedelete1, dirmove1
       
   675 
       
   676 
       
   677 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
       
   678     """Finds moved directories and files that should move with them.
       
   679 
       
   680     ctx: the context for one of the sides
       
   681     copy: files copied on the same side (as ctx)
       
   682     fullcopy: files copied on the same side (as ctx), including those that
       
   683               merge.manifestmerge() won't care about
       
   684     addedfiles: added files on the other side (compared to ctx)
       
   685     """
   666     # generate a directory move map
   686     # generate a directory move map
   667     d1, d2 = c1.dirs(), c2.dirs()
   687     d = ctx.dirs()
   668     invalid = set()
   688     invalid = set()
   669     dirmove = {}
   689     dirmove = {}
   670 
   690 
   671     # examine each file copy for a potential directory move, which is
   691     # examine each file copy for a potential directory move, which is
   672     # when all the files in a directory are moved to a new directory
   692     # when all the files in a directory are moved to a new directory
   673     for dst, src in pycompat.iteritems(fullcopy):
   693     for dst, src in pycompat.iteritems(fullcopy):
   674         dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
   694         dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
   675         if dsrc in invalid:
   695         if dsrc in invalid:
   676             # already seen to be uninteresting
   696             # already seen to be uninteresting
   677             continue
   697             continue
   678         elif dsrc in d1 and ddst in d1:
   698         elif dsrc in d and ddst in d:
   679             # directory wasn't entirely moved locally
   699             # directory wasn't entirely moved locally
   680             invalid.add(dsrc)
       
   681         elif dsrc in d2 and ddst in d2:
       
   682             # directory wasn't entirely moved remotely
       
   683             invalid.add(dsrc)
   700             invalid.add(dsrc)
   684         elif dsrc in dirmove and dirmove[dsrc] != ddst:
   701         elif dsrc in dirmove and dirmove[dsrc] != ddst:
   685             # files from the same directory moved to two different places
   702             # files from the same directory moved to two different places
   686             invalid.add(dsrc)
   703             invalid.add(dsrc)
   687         else:
   704         else:
   689             dirmove[dsrc] = ddst
   706             dirmove[dsrc] = ddst
   690 
   707 
   691     for i in invalid:
   708     for i in invalid:
   692         if i in dirmove:
   709         if i in dirmove:
   693             del dirmove[i]
   710             del dirmove[i]
   694     del d1, d2, invalid
   711     del d, invalid
   695 
   712 
   696     if not dirmove:
   713     if not dirmove:
   697         return {}, {}
   714         return {}, {}
   698 
   715 
   699     dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
   716     dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
   703             b"   discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d])
   720             b"   discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d])
   704         )
   721         )
   705 
   722 
   706     movewithdir = {}
   723     movewithdir = {}
   707     # check unaccounted nonoverlapping files against directory moves
   724     # check unaccounted nonoverlapping files against directory moves
   708     for f in u1 + u2:
   725     for f in addedfiles:
   709         if f not in fullcopy:
   726         if f not in fullcopy:
   710             for d in dirmove:
   727             for d in dirmove:
   711                 if f.startswith(d):
   728                 if f.startswith(d):
   712                     # new file added in a directory that was moved, move it
   729                     # new file added in a directory that was moved, move it
   713                     df = dirmove[d] + f[len(d) :]
   730                     df = dirmove[d] + f[len(d) :]