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: |