--- a/mercurial/copies.py Wed Oct 12 11:54:03 2016 +0200
+++ b/mercurial/copies.py Tue Oct 04 12:51:54 2016 +0200
@@ -289,6 +289,22 @@
return fctx
return util.lrucachefunc(makectx)
+def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
+ """combine partial copy paths"""
+ remainder = {}
+ for f in copyfrom:
+ if f in copyto:
+ finalcopy[copyto[f]] = copyfrom[f]
+ del copyto[f]
+ for f in incompletediverge:
+ assert f not in diverge
+ ic = incompletediverge[f]
+ if ic[0] in copyto:
+ diverge[f] = [copyto[ic[0]], ic[1]]
+ else:
+ remainder[f] = ic
+ return remainder
+
def mergecopies(repo, c1, c2, base):
"""
Find moves and copies between context c1 and c2 that are relevant
@@ -360,14 +376,21 @@
# - diverge = record all diverges in this dict
# - copy = record all non-divergent copies in this dict
# - fullcopy = record all copies in this dict
+ # - incomplete = record non-divergent partial copies here
+ # - incompletediverge = record divergent partial copies here
diverge = {} # divergence data is shared
+ incompletediverge = {}
data1 = {'copy': {},
'fullcopy': {},
+ 'incomplete': {},
'diverge': diverge,
+ 'incompletediverge': incompletediverge,
}
data2 = {'copy': {},
'fullcopy': {},
+ 'incomplete': {},
'diverge': diverge,
+ 'incompletediverge': incompletediverge,
}
# find interesting file sets from manifests
@@ -398,6 +421,13 @@
copy = dict(data1['copy'].items() + data2['copy'].items())
fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
+ if dirtyc1:
+ _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
+ incompletediverge)
+ else:
+ _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
+ incompletediverge)
+
renamedelete = {}
renamedeleteset = set()
divergeset = set()
@@ -416,13 +446,36 @@
repo.ui.debug(" unmatched files new in both:\n %s\n"
% "\n ".join(bothnew))
bothdiverge = {}
- bothdata = {'copy': {},
- 'fullcopy': {},
- 'diverge': bothdiverge,
- }
+ bothincompletediverge = {}
+ both1 = {'copy': {},
+ 'fullcopy': {},
+ 'incomplete': {},
+ 'diverge': bothdiverge,
+ 'incompletediverge': bothincompletediverge
+ }
+ both2 = {'copy': {},
+ 'fullcopy': {},
+ 'incomplete': {},
+ 'diverge': bothdiverge,
+ 'incompletediverge': bothincompletediverge
+ }
for f in bothnew:
- _checkcopies(c1, f, m1, m2, base, tca, limit, bothdata)
- _checkcopies(c2, f, m2, m1, base, tca, limit, bothdata)
+ _checkcopies(c1, f, m1, m2, base, tca, limit, both1)
+ _checkcopies(c2, f, m2, m1, base, tca, limit, both2)
+ if dirtyc1:
+ assert both2['incomplete'] == {}
+ remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
+ bothincompletediverge)
+ else:
+ assert both1['incomplete'] == {}
+ remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
+ bothincompletediverge)
+ for f in remainder:
+ assert f not in bothdiverge
+ ic = remainder[f]
+ if ic[0] in (m1 if dirtyc1 else m2):
+ # backed-out rename on one side, but watch out for deleted files
+ bothdiverge[f] = ic
for of, fl in bothdiverge.items():
if len(fl) == 2 and fl[0] == fl[1]:
copy[fl[0]] = of # not actually divergent, just matching renames