mercurial/copies.py
changeset 43252 32187ae9eeb3
parent 43231 30570a056fa8
child 43253 82dabad535d2
equal deleted inserted replaced
43251:970978975574 43252:32187ae9eeb3
   194                 children[p] = [r]
   194                 children[p] = [r]
   195             else:
   195             else:
   196                 children[p].append(r)
   196                 children[p].append(r)
   197 
   197 
   198     roots = set(children) - set(missingrevs)
   198     roots = set(children) - set(missingrevs)
   199     # 'work' contains 3-tuples of a (revision number, parent number, copies).
   199     work = list(roots)
   200     # The parent number is only used for knowing which parent the copies dict
   200     all_copies = {r: {} for r in roots}
   201     # came from.
       
   202     # NOTE: To reduce costly copying the 'copies' dicts, we reuse the same
       
   203     # instance for *one* of the child nodes (the last one). Once an instance
       
   204     # has been put on the queue, it is thus no longer safe to modify it.
       
   205     # Conversely, it *is* safe to modify an instance popped off the queue.
       
   206     work = [(r, 1, {}) for r in roots]
       
   207     heapq.heapify(work)
   201     heapq.heapify(work)
   208     alwaysmatch = match.always()
   202     alwaysmatch = match.always()
   209     while work:
   203     while work:
   210         r, i1, copies = heapq.heappop(work)
   204         r = heapq.heappop(work)
   211         if work and work[0][0] == r:
   205         copies = all_copies.pop(r)
   212             # We are tracing copies from both parents
       
   213             r, i2, copies2 = heapq.heappop(work)
       
   214             for dst, src in copies2.items():
       
   215                 # Unlike when copies are stored in the filelog, we consider
       
   216                 # it a copy even if the destination already existed on the
       
   217                 # other branch. It's simply too expensive to check if the
       
   218                 # file existed in the manifest.
       
   219                 if dst not in copies:
       
   220                     # If it was copied on the p1 side, leave it as copied from
       
   221                     # that side, even if it was also copied on the p2 side.
       
   222                     copies[dst] = copies2[dst]
       
   223         if r == b.rev():
   206         if r == b.rev():
   224             return copies
   207             return copies
   225         for i, c in enumerate(children[r]):
   208         for i, c in enumerate(children[r]):
   226             childctx = repo[c]
   209             childctx = repo[c]
   227             if r == childctx.p1().rev():
   210             if r == childctx.p1().rev():
   243             if childcopies:
   226             if childcopies:
   244                 newcopies = _chain(newcopies, childcopies)
   227                 newcopies = _chain(newcopies, childcopies)
   245             for f in childctx.filesremoved():
   228             for f in childctx.filesremoved():
   246                 if f in newcopies:
   229                 if f in newcopies:
   247                     del newcopies[f]
   230                     del newcopies[f]
   248             heapq.heappush(work, (c, parent, newcopies))
   231             othercopies = all_copies.get(c)
       
   232             if othercopies is None:
       
   233                 heapq.heappush(work, c)
       
   234                 all_copies[c] = newcopies
       
   235             else:
       
   236                 # we are the second parent to work on c, we need to merge our
       
   237                 # work with the other.
       
   238                 #
       
   239                 # Unlike when copies are stored in the filelog, we consider
       
   240                 # it a copy even if the destination already existed on the
       
   241                 # other branch. It's simply too expensive to check if the
       
   242                 # file existed in the manifest.
       
   243                 #
       
   244                 # In case of conflict, parent 1 take precedence over parent 2.
       
   245                 # This is an arbitrary choice made anew when implementing
       
   246                 # changeset based copies. It was made without regards with
       
   247                 # potential filelog related behavior.
       
   248                 if parent == 1:
       
   249                     othercopies.update(newcopies)
       
   250                 else:
       
   251                     newcopies.update(othercopies)
       
   252                     all_copies[c] = newcopies
   249     assert False
   253     assert False
   250 
   254 
   251 
   255 
   252 def _forwardcopies(a, b, base=None, match=None):
   256 def _forwardcopies(a, b, base=None, match=None):
   253     """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
   257     """find {dst@b: src@a} copy mapping where a is an ancestor of b"""