comparison mercurial/copies.py @ 30202:a005c33d0bd7

mergecopies: add logic to process incomplete data We first combine incomplete copies on the two sides of the topological CA into complete copies. Any leftover incomplete copies are then combined with the incomplete divergences to reconstruct divergences spanning over the topological CA. Finally we promote any divergences falsely flagged as incomplete to full divergences. Right now, there is nothing generating incomplete copy/divergence data, so this code does nothing. Changes to _checkcopies to populate these dicts are coming later in this series.
author Gábor Stefanik <gabor.stefanik@nng.com>
date Tue, 04 Oct 2016 12:51:54 +0200
parents 856ead835f56
children b94b92f0c683
comparison
equal deleted inserted replaced
30201:856ead835f56 30202:a005c33d0bd7
287 fctx._ancestrycontext = ac 287 fctx._ancestrycontext = ac
288 fctx._descendantrev = rev 288 fctx._descendantrev = rev
289 return fctx 289 return fctx
290 return util.lrucachefunc(makectx) 290 return util.lrucachefunc(makectx)
291 291
292 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
293 """combine partial copy paths"""
294 remainder = {}
295 for f in copyfrom:
296 if f in copyto:
297 finalcopy[copyto[f]] = copyfrom[f]
298 del copyto[f]
299 for f in incompletediverge:
300 assert f not in diverge
301 ic = incompletediverge[f]
302 if ic[0] in copyto:
303 diverge[f] = [copyto[ic[0]], ic[1]]
304 else:
305 remainder[f] = ic
306 return remainder
307
292 def mergecopies(repo, c1, c2, base): 308 def mergecopies(repo, c1, c2, base):
293 """ 309 """
294 Find moves and copies between context c1 and c2 that are relevant 310 Find moves and copies between context c1 and c2 that are relevant
295 for merging. 'base' will be used as the merge base. 311 for merging. 'base' will be used as the merge base.
296 312
358 374
359 # gather data from _checkcopies: 375 # gather data from _checkcopies:
360 # - diverge = record all diverges in this dict 376 # - diverge = record all diverges in this dict
361 # - copy = record all non-divergent copies in this dict 377 # - copy = record all non-divergent copies in this dict
362 # - fullcopy = record all copies in this dict 378 # - fullcopy = record all copies in this dict
379 # - incomplete = record non-divergent partial copies here
380 # - incompletediverge = record divergent partial copies here
363 diverge = {} # divergence data is shared 381 diverge = {} # divergence data is shared
382 incompletediverge = {}
364 data1 = {'copy': {}, 383 data1 = {'copy': {},
365 'fullcopy': {}, 384 'fullcopy': {},
385 'incomplete': {},
366 'diverge': diverge, 386 'diverge': diverge,
387 'incompletediverge': incompletediverge,
367 } 388 }
368 data2 = {'copy': {}, 389 data2 = {'copy': {},
369 'fullcopy': {}, 390 'fullcopy': {},
391 'incomplete': {},
370 'diverge': diverge, 392 'diverge': diverge,
393 'incompletediverge': incompletediverge,
371 } 394 }
372 395
373 # find interesting file sets from manifests 396 # find interesting file sets from manifests
374 addedinm1 = m1.filesnotin(mb) 397 addedinm1 = m1.filesnotin(mb)
375 addedinm2 = m2.filesnotin(mb) 398 addedinm2 = m2.filesnotin(mb)
396 _checkcopies(c2, f, m2, m1, base, tca, limit, data2) 419 _checkcopies(c2, f, m2, m1, base, tca, limit, data2)
397 420
398 copy = dict(data1['copy'].items() + data2['copy'].items()) 421 copy = dict(data1['copy'].items() + data2['copy'].items())
399 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items()) 422 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
400 423
424 if dirtyc1:
425 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
426 incompletediverge)
427 else:
428 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
429 incompletediverge)
430
401 renamedelete = {} 431 renamedelete = {}
402 renamedeleteset = set() 432 renamedeleteset = set()
403 divergeset = set() 433 divergeset = set()
404 for of, fl in diverge.items(): 434 for of, fl in diverge.items():
405 if len(fl) == 1 or of in c1 or of in c2: 435 if len(fl) == 1 or of in c1 or of in c2:
414 444
415 if bothnew: 445 if bothnew:
416 repo.ui.debug(" unmatched files new in both:\n %s\n" 446 repo.ui.debug(" unmatched files new in both:\n %s\n"
417 % "\n ".join(bothnew)) 447 % "\n ".join(bothnew))
418 bothdiverge = {} 448 bothdiverge = {}
419 bothdata = {'copy': {}, 449 bothincompletediverge = {}
420 'fullcopy': {}, 450 both1 = {'copy': {},
421 'diverge': bothdiverge, 451 'fullcopy': {},
422 } 452 'incomplete': {},
453 'diverge': bothdiverge,
454 'incompletediverge': bothincompletediverge
455 }
456 both2 = {'copy': {},
457 'fullcopy': {},
458 'incomplete': {},
459 'diverge': bothdiverge,
460 'incompletediverge': bothincompletediverge
461 }
423 for f in bothnew: 462 for f in bothnew:
424 _checkcopies(c1, f, m1, m2, base, tca, limit, bothdata) 463 _checkcopies(c1, f, m1, m2, base, tca, limit, both1)
425 _checkcopies(c2, f, m2, m1, base, tca, limit, bothdata) 464 _checkcopies(c2, f, m2, m1, base, tca, limit, both2)
465 if dirtyc1:
466 assert both2['incomplete'] == {}
467 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
468 bothincompletediverge)
469 else:
470 assert both1['incomplete'] == {}
471 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
472 bothincompletediverge)
473 for f in remainder:
474 assert f not in bothdiverge
475 ic = remainder[f]
476 if ic[0] in (m1 if dirtyc1 else m2):
477 # backed-out rename on one side, but watch out for deleted files
478 bothdiverge[f] = ic
426 for of, fl in bothdiverge.items(): 479 for of, fl in bothdiverge.items():
427 if len(fl) == 2 and fl[0] == fl[1]: 480 if len(fl) == 2 and fl[0] == fl[1]:
428 copy[fl[0]] = of # not actually divergent, just matching renames 481 copy[fl[0]] = of # not actually divergent, just matching renames
429 482
430 if fullcopy and repo.ui.debugflag: 483 if fullcopy and repo.ui.debugflag: