mercurial/copies.py
changeset 19178 4327687ca757
parent 18899 d8ff607ef721
child 20294 243ea5ffdf31
equal deleted inserted replaced
19177:1e104aaa4c44 19178:4327687ca757
   220     copy = {}
   220     copy = {}
   221     movewithdir = {}
   221     movewithdir = {}
   222     fullcopy = {}
   222     fullcopy = {}
   223     diverge = {}
   223     diverge = {}
   224 
   224 
   225     def related(f1, f2, limit):
   225     def _checkcopies(f, m1, m2):
   226         # Walk back to common ancestor to see if the two files originate
   226         checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy)
   227         # from the same file. Since workingfilectx's rev() is None it messes
       
   228         # up the integer comparison logic, hence the pre-step check for
       
   229         # None (f1 and f2 can only be workingfilectx's initially).
       
   230 
       
   231         if f1 == f2:
       
   232             return f1 # a match
       
   233 
       
   234         g1, g2 = f1.ancestors(), f2.ancestors()
       
   235         try:
       
   236             f1r, f2r = f1.rev(), f2.rev()
       
   237 
       
   238             if f1r is None:
       
   239                 f1 = g1.next()
       
   240             if f2r is None:
       
   241                 f2 = g2.next()
       
   242 
       
   243             while True:
       
   244                 f1r, f2r = f1.rev(), f2.rev()
       
   245                 if f1r > f2r:
       
   246                     f1 = g1.next()
       
   247                 elif f2r > f1r:
       
   248                     f2 = g2.next()
       
   249                 elif f1 == f2:
       
   250                     return f1 # a match
       
   251                 elif f1r == f2r or f1r < limit or f2r < limit:
       
   252                     return False # copy no longer relevant
       
   253         except StopIteration:
       
   254             return False
       
   255 
       
   256     def checkcopies(f, m1, m2):
       
   257         '''check possible copies of f from m1 to m2'''
       
   258         of = None
       
   259         seen = set([f])
       
   260         for oc in ctx(f, m1[f]).ancestors():
       
   261             ocr = oc.rev()
       
   262             of = oc.path()
       
   263             if of in seen:
       
   264                 # check limit late - grab last rename before
       
   265                 if ocr < limit:
       
   266                     break
       
   267                 continue
       
   268             seen.add(of)
       
   269 
       
   270             fullcopy[f] = of # remember for dir rename detection
       
   271             if of not in m2:
       
   272                 continue # no match, keep looking
       
   273             if m2[of] == ma.get(of):
       
   274                 break # no merge needed, quit early
       
   275             c2 = ctx(of, m2[of])
       
   276             cr = related(oc, c2, ca.rev())
       
   277             if cr and (of == f or of == c2.path()): # non-divergent
       
   278                 copy[f] = of
       
   279                 of = None
       
   280                 break
       
   281 
       
   282         if of in ma:
       
   283             diverge.setdefault(of, []).append(f)
       
   284 
   227 
   285     repo.ui.debug("  searching for copies back to rev %d\n" % limit)
   228     repo.ui.debug("  searching for copies back to rev %d\n" % limit)
   286 
   229 
   287     u1 = _nonoverlap(m1, m2, ma)
   230     u1 = _nonoverlap(m1, m2, ma)
   288     u2 = _nonoverlap(m2, m1, ma)
   231     u2 = _nonoverlap(m2, m1, ma)
   293     if u2:
   236     if u2:
   294         repo.ui.debug("  unmatched files in other:\n   %s\n"
   237         repo.ui.debug("  unmatched files in other:\n   %s\n"
   295                       % "\n   ".join(u2))
   238                       % "\n   ".join(u2))
   296 
   239 
   297     for f in u1:
   240     for f in u1:
   298         checkcopies(f, m1, m2)
   241         _checkcopies(f, m1, m2)
   299     for f in u2:
   242     for f in u2:
   300         checkcopies(f, m2, m1)
   243         _checkcopies(f, m2, m1)
   301 
   244 
   302     renamedelete = {}
   245     renamedelete = {}
   303     renamedelete2 = set()
   246     renamedelete2 = set()
   304     diverge2 = set()
   247     diverge2 = set()
   305     for of, fl in diverge.items():
   248     for of, fl in diverge.items():
   384                         repo.ui.debug(("   pending file src: '%s' -> "
   327                         repo.ui.debug(("   pending file src: '%s' -> "
   385                                        "dst: '%s'\n") % (f, df))
   328                                        "dst: '%s'\n") % (f, df))
   386                     break
   329                     break
   387 
   330 
   388     return copy, movewithdir, diverge, renamedelete
   331     return copy, movewithdir, diverge, renamedelete
       
   332 
       
   333 def checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy):
       
   334     """
       
   335     check possible copies of f from m1 to m2
       
   336 
       
   337     ctx = function accepting (filename, node) that returns a filectx.
       
   338     f = the filename to check
       
   339     m1 = the source manifest
       
   340     m2 = the destination manifest
       
   341     ca = the changectx of the common ancestor
       
   342     limit = the rev number to not search beyond
       
   343     diverge = record all diverges in this dict
       
   344     copy = record all non-divergent copies in this dict
       
   345     fullcopy = record all copies in this dict
       
   346     """
       
   347 
       
   348     ma = ca.manifest()
       
   349 
       
   350     def _related(f1, f2, limit):
       
   351         # Walk back to common ancestor to see if the two files originate
       
   352         # from the same file. Since workingfilectx's rev() is None it messes
       
   353         # up the integer comparison logic, hence the pre-step check for
       
   354         # None (f1 and f2 can only be workingfilectx's initially).
       
   355 
       
   356         if f1 == f2:
       
   357             return f1 # a match
       
   358 
       
   359         g1, g2 = f1.ancestors(), f2.ancestors()
       
   360         try:
       
   361             f1r, f2r = f1.rev(), f2.rev()
       
   362 
       
   363             if f1r is None:
       
   364                 f1 = g1.next()
       
   365             if f2r is None:
       
   366                 f2 = g2.next()
       
   367 
       
   368             while True:
       
   369                 f1r, f2r = f1.rev(), f2.rev()
       
   370                 if f1r > f2r:
       
   371                     f1 = g1.next()
       
   372                 elif f2r > f1r:
       
   373                     f2 = g2.next()
       
   374                 elif f1 == f2:
       
   375                     return f1 # a match
       
   376                 elif f1r == f2r or f1r < limit or f2r < limit:
       
   377                     return False # copy no longer relevant
       
   378         except StopIteration:
       
   379             return False
       
   380 
       
   381     of = None
       
   382     seen = set([f])
       
   383     for oc in ctx(f, m1[f]).ancestors():
       
   384         ocr = oc.rev()
       
   385         of = oc.path()
       
   386         if of in seen:
       
   387             # check limit late - grab last rename before
       
   388             if ocr < limit:
       
   389                 break
       
   390             continue
       
   391         seen.add(of)
       
   392 
       
   393         fullcopy[f] = of # remember for dir rename detection
       
   394         if of not in m2:
       
   395             continue # no match, keep looking
       
   396         if m2[of] == ma.get(of):
       
   397             break # no merge needed, quit early
       
   398         c2 = ctx(of, m2[of])
       
   399         cr = _related(oc, c2, ca.rev())
       
   400         if cr and (of == f or of == c2.path()): # non-divergent
       
   401             copy[f] = of
       
   402             of = None
       
   403             break
       
   404 
       
   405     if of in ma:
       
   406         diverge.setdefault(of, []).append(f)