Show More
@@ -410,14 +410,13 b' def overridecalculateupdates(origfn, rep' | |||||
410 | if overwrite: |
|
410 | if overwrite: | |
411 | return actions |
|
411 | return actions | |
412 |
|
412 | |||
413 |
removes = set(a[0] for a in actions |
|
413 | removes = set(a[0] for a in actions['r']) | |
414 | processed = [] |
|
|||
415 |
|
414 | |||
416 | for action in actions: |
|
415 | newglist = [] | |
417 | f, m, args, msg = action |
|
416 | for action in actions['g']: | |
418 |
|
417 | f, args, msg = action | ||
419 | splitstandin = f and lfutil.splitstandin(f) |
|
418 | splitstandin = f and lfutil.splitstandin(f) | |
420 |
if ( |
|
419 | if (splitstandin is not None and | |
421 | splitstandin in p1 and splitstandin not in removes): |
|
420 | splitstandin in p1 and splitstandin not in removes): | |
422 | # Case 1: normal file in the working copy, largefile in |
|
421 | # Case 1: normal file in the working copy, largefile in | |
423 | # the second parent |
|
422 | # the second parent | |
@@ -427,12 +426,11 b' def overridecalculateupdates(origfn, rep' | |||||
427 | 'use (l)argefile or keep (n)ormal file?' |
|
426 | 'use (l)argefile or keep (n)ormal file?' | |
428 | '$$ &Largefile $$ &Normal file') % lfile |
|
427 | '$$ &Largefile $$ &Normal file') % lfile | |
429 | if repo.ui.promptchoice(msg, 0) == 0: |
|
428 | if repo.ui.promptchoice(msg, 0) == 0: | |
430 |
|
|
429 | actions['r'].append((lfile, None, msg)) | |
431 |
|
|
430 | newglist.append((standin, (p2.flags(standin),), msg)) | |
432 | else: |
|
431 | else: | |
433 |
|
|
432 | actions['r'].append((standin, None, msg)) | |
434 | elif (m == "g" and |
|
433 | elif lfutil.standin(f) in p1 and lfutil.standin(f) not in removes: | |
435 | lfutil.standin(f) in p1 and lfutil.standin(f) not in removes): |
|
|||
436 | # Case 2: largefile in the working copy, normal file in |
|
434 | # Case 2: largefile in the working copy, normal file in | |
437 | # the second parent |
|
435 | # the second parent | |
438 | standin = lfutil.standin(f) |
|
436 | standin = lfutil.standin(f) | |
@@ -441,14 +439,17 b' def overridecalculateupdates(origfn, rep' | |||||
441 | 'keep (l)argefile or use (n)ormal file?' |
|
439 | 'keep (l)argefile or use (n)ormal file?' | |
442 | '$$ &Largefile $$ &Normal file') % lfile |
|
440 | '$$ &Largefile $$ &Normal file') % lfile | |
443 | if repo.ui.promptchoice(msg, 0) == 0: |
|
441 | if repo.ui.promptchoice(msg, 0) == 0: | |
444 |
|
|
442 | actions['r'].append((lfile, None, msg)) | |
|
443 | else: | |||
|
444 | actions['r'].append((standin, None, msg)) | |||
|
445 | newglist.append((lfile, (p2.flags(lfile),), msg)) | |||
445 |
|
|
446 | else: | |
446 | processed.append((standin, "r", None, msg)) |
|
447 | newglist.append(action) | |
447 | processed.append((lfile, "g", (p2.flags(lfile),), msg)) |
|
|||
448 | else: |
|
|||
449 | processed.append(action) |
|
|||
450 |
|
448 | |||
451 | return processed |
|
449 | newglist.sort() | |
|
450 | actions['g'] = newglist | |||
|
451 | ||||
|
452 | return actions | |||
452 |
|
453 | |||
453 | # Override filemerge to prompt the user about how they wish to merge |
|
454 | # Override filemerge to prompt the user about how they wish to merge | |
454 | # largefiles. This will handle identical edits without prompting the user. |
|
455 | # largefiles. This will handle identical edits without prompting the user. |
@@ -331,63 +331,45 b' def _forgetremoved(wctx, mctx, branchmer' | |||||
331 | as removed. |
|
331 | as removed. | |
332 | """ |
|
332 | """ | |
333 |
|
333 | |||
334 | actions = [] |
|
334 | ractions = [] | |
335 | state = branchmerge and 'r' or 'f' |
|
335 | factions = xactions = [] | |
|
336 | if branchmerge: | |||
|
337 | xactions = ractions | |||
336 | for f in wctx.deleted(): |
|
338 | for f in wctx.deleted(): | |
337 | if f not in mctx: |
|
339 | if f not in mctx: | |
338 |
actions.append((f |
|
340 | xactions.append((f, None, "forget deleted")) | |
339 |
|
341 | |||
340 | if not branchmerge: |
|
342 | if not branchmerge: | |
341 | for f in wctx.removed(): |
|
343 | for f in wctx.removed(): | |
342 | if f not in mctx: |
|
344 | if f not in mctx: | |
343 |
actions.append((f |
|
345 | factions.append((f, None, "forget removed")) | |
344 |
|
346 | |||
345 | return actions |
|
347 | return ractions, factions | |
346 |
|
348 | |||
347 | def _checkcollision(repo, wmf, actions): |
|
349 | def _checkcollision(repo, wmf, actions): | |
348 | # build provisional merged manifest up |
|
350 | # build provisional merged manifest up | |
349 | pmmf = set(wmf) |
|
351 | pmmf = set(wmf) | |
350 |
|
352 | |||
351 | def addop(f, args): |
|
353 | if actions: | |
|
354 | # k, dr, e and rd are no-op | |||
|
355 | for m in 'a', 'f', 'g', 'cd', 'dc': | |||
|
356 | for f, args, msg in actions[m]: | |||
352 | pmmf.add(f) |
|
357 | pmmf.add(f) | |
353 | def removeop(f, args): |
|
358 | for f, args, msg in actions['r']: | |
354 | pmmf.discard(f) |
|
359 | pmmf.discard(f) | |
355 | def nop(f, args): |
|
360 | for f, args, msg in actions['dm']: | |
356 | pass |
|
|||
357 |
|
||||
358 | def renamemoveop(f, args): |
|
|||
359 | f2, flags = args |
|
361 | f2, flags = args | |
360 | pmmf.discard(f2) |
|
362 | pmmf.discard(f2) | |
361 | pmmf.add(f) |
|
363 | pmmf.add(f) | |
362 | def renamegetop(f, args): |
|
364 | for f, args, msg in actions['dg']: | |
363 | f2, flags = args |
|
365 | f2, flags = args | |
364 | pmmf.add(f) |
|
366 | pmmf.add(f) | |
365 | def mergeop(f, args): |
|
367 | for f, args, msg in actions['m']: | |
366 | f1, f2, fa, move, anc = args |
|
368 | f1, f2, fa, move, anc = args | |
367 | if move: |
|
369 | if move: | |
368 | pmmf.discard(f1) |
|
370 | pmmf.discard(f1) | |
369 | pmmf.add(f) |
|
371 | pmmf.add(f) | |
370 |
|
372 | |||
371 | opmap = { |
|
|||
372 | "a": addop, |
|
|||
373 | "dm": renamemoveop, |
|
|||
374 | "dg": renamegetop, |
|
|||
375 | "dr": nop, |
|
|||
376 | "e": nop, |
|
|||
377 | "k": nop, |
|
|||
378 | "f": addop, # untracked file should be kept in working directory |
|
|||
379 | "g": addop, |
|
|||
380 | "m": mergeop, |
|
|||
381 | "r": removeop, |
|
|||
382 | "rd": nop, |
|
|||
383 | "cd": addop, |
|
|||
384 | "dc": addop, |
|
|||
385 | } |
|
|||
386 | for f, m, args, msg in actions: |
|
|||
387 | op = opmap.get(m) |
|
|||
388 | assert op, m |
|
|||
389 | op(f, args) |
|
|||
390 |
|
||||
391 | # check case-folding collision in provisional merged manifest |
|
373 | # check case-folding collision in provisional merged manifest | |
392 | foldmap = {} |
|
374 | foldmap = {} | |
393 | for f in sorted(pmmf): |
|
375 | for f in sorted(pmmf): | |
@@ -407,7 +389,8 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
407 | acceptremote = accept the incoming changes without prompting |
|
389 | acceptremote = accept the incoming changes without prompting | |
408 | """ |
|
390 | """ | |
409 |
|
391 | |||
410 | actions, copy, movewithdir = [], {}, {} |
|
392 | actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split()) | |
|
393 | copy, movewithdir = {}, {} | |||
411 |
|
394 | |||
412 | # manifests fetched in order are going to be faster, so prime the caches |
|
395 | # manifests fetched in order are going to be faster, so prime the caches | |
413 | [x.manifest() for x in |
|
396 | [x.manifest() for x in | |
@@ -417,9 +400,9 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
417 | ret = copies.mergecopies(repo, wctx, p2, pa) |
|
400 | ret = copies.mergecopies(repo, wctx, p2, pa) | |
418 | copy, movewithdir, diverge, renamedelete = ret |
|
401 | copy, movewithdir, diverge, renamedelete = ret | |
419 | for of, fl in diverge.iteritems(): |
|
402 | for of, fl in diverge.iteritems(): | |
420 |
actions.append((of |
|
403 | actions['dr'].append((of, (fl,), "divergent renames")) | |
421 | for of, fl in renamedelete.iteritems(): |
|
404 | for of, fl in renamedelete.iteritems(): | |
422 |
actions.append((of |
|
405 | actions['rd'].append((of, (fl,), "rename and delete")) | |
423 |
|
406 | |||
424 | repo.ui.note(_("resolving manifests\n")) |
|
407 | repo.ui.note(_("resolving manifests\n")) | |
425 | repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n" |
|
408 | repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n" | |
@@ -471,50 +454,50 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
471 | fla = ma.flags(fa) |
|
454 | fla = ma.flags(fa) | |
472 | nol = 'l' not in fl1 + fl2 + fla |
|
455 | nol = 'l' not in fl1 + fl2 + fla | |
473 | if n2 == a and fl2 == fla: |
|
456 | if n2 == a and fl2 == fla: | |
474 |
actions.append((f |
|
457 | actions['k'].append((f, (), "keep")) # remote unchanged | |
475 | elif n1 == a and fl1 == fla: # local unchanged - use remote |
|
458 | elif n1 == a and fl1 == fla: # local unchanged - use remote | |
476 | if n1 == n2: # optimization: keep local content |
|
459 | if n1 == n2: # optimization: keep local content | |
477 |
actions.append((f |
|
460 | actions['e'].append((f, (fl2,), "update permissions")) | |
478 | else: |
|
461 | else: | |
479 |
actions.append((f |
|
462 | actions['g'].append((f, (fl2,), "remote is newer")) | |
480 | elif nol and n2 == a: # remote only changed 'x' |
|
463 | elif nol and n2 == a: # remote only changed 'x' | |
481 |
actions.append((f |
|
464 | actions['e'].append((f, (fl2,), "update permissions")) | |
482 | elif nol and n1 == a: # local only changed 'x' |
|
465 | elif nol and n1 == a: # local only changed 'x' | |
483 |
actions.append((f |
|
466 | actions['g'].append((f, (fl1,), "remote is newer")) | |
484 | else: # both changed something |
|
467 | else: # both changed something | |
485 |
actions.append((f |
|
468 | actions['m'].append((f, (f, f, fa, False, pa.node()), | |
486 | "versions differ")) |
|
469 | "versions differ")) | |
487 | elif f in copied: # files we'll deal with on m2 side |
|
470 | elif f in copied: # files we'll deal with on m2 side | |
488 | pass |
|
471 | pass | |
489 | elif n1 and f in movewithdir: # directory rename, move local |
|
472 | elif n1 and f in movewithdir: # directory rename, move local | |
490 | f2 = movewithdir[f] |
|
473 | f2 = movewithdir[f] | |
491 |
actions.append((f2 |
|
474 | actions['dm'].append((f2, (f, fl1), | |
492 | "remote directory rename - move from " + f)) |
|
475 | "remote directory rename - move from " + f)) | |
493 | elif n1 and f in copy: |
|
476 | elif n1 and f in copy: | |
494 | f2 = copy[f] |
|
477 | f2 = copy[f] | |
495 |
actions.append((f |
|
478 | actions['m'].append((f, (f, f2, f2, False, pa.node()), | |
496 | "local copied/moved from " + f2)) |
|
479 | "local copied/moved from " + f2)) | |
497 | elif n1 and f in ma: # clean, a different, no remote |
|
480 | elif n1 and f in ma: # clean, a different, no remote | |
498 | if n1 != ma[f]: |
|
481 | if n1 != ma[f]: | |
499 | if acceptremote: |
|
482 | if acceptremote: | |
500 |
actions.append((f |
|
483 | actions['r'].append((f, None, "remote delete")) | |
501 | else: |
|
484 | else: | |
502 |
actions.append((f |
|
485 | actions['cd'].append((f, None, "prompt changed/deleted")) | |
503 | elif n1[20:] == "a": # added, no remote |
|
486 | elif n1[20:] == "a": # added, no remote | |
504 |
actions.append((f |
|
487 | actions['f'].append((f, None, "remote deleted")) | |
505 | else: |
|
488 | else: | |
506 |
actions.append((f |
|
489 | actions['r'].append((f, None, "other deleted")) | |
507 | elif n2 and f in movewithdir: |
|
490 | elif n2 and f in movewithdir: | |
508 | f2 = movewithdir[f] |
|
491 | f2 = movewithdir[f] | |
509 |
actions.append((f2 |
|
492 | actions['dg'].append((f2, (f, fl2), | |
510 | "local directory rename - get from " + f)) |
|
493 | "local directory rename - get from " + f)) | |
511 | elif n2 and f in copy: |
|
494 | elif n2 and f in copy: | |
512 | f2 = copy[f] |
|
495 | f2 = copy[f] | |
513 | if f2 in m2: |
|
496 | if f2 in m2: | |
514 |
actions.append((f |
|
497 | actions['m'].append((f, (f2, f, f2, False, pa.node()), | |
515 | "remote copied from " + f2)) |
|
498 | "remote copied from " + f2)) | |
516 | else: |
|
499 | else: | |
517 |
actions.append((f |
|
500 | actions['m'].append((f, (f2, f, f2, True, pa.node()), | |
518 | "remote moved from " + f2)) |
|
501 | "remote moved from " + f2)) | |
519 | elif n2 and f not in ma: |
|
502 | elif n2 and f not in ma: | |
520 | # local unknown, remote created: the logic is described by the |
|
503 | # local unknown, remote created: the logic is described by the | |
@@ -530,17 +513,17 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
530 | # Checking whether the files are different is expensive, so we |
|
513 | # Checking whether the files are different is expensive, so we | |
531 | # don't do that when we can avoid it. |
|
514 | # don't do that when we can avoid it. | |
532 | if force and not branchmerge: |
|
515 | if force and not branchmerge: | |
533 |
actions.append((f |
|
516 | actions['g'].append((f, (fl2,), "remote created")) | |
534 | else: |
|
517 | else: | |
535 | different = _checkunknownfile(repo, wctx, p2, f) |
|
518 | different = _checkunknownfile(repo, wctx, p2, f) | |
536 | if force and branchmerge and different: |
|
519 | if force and branchmerge and different: | |
537 | # FIXME: This is wrong - f is not in ma ... |
|
520 | # FIXME: This is wrong - f is not in ma ... | |
538 |
actions.append((f |
|
521 | actions['m'].append((f, (f, f, f, False, pa.node()), | |
539 | "remote differs from untracked local")) |
|
522 | "remote differs from untracked local")) | |
540 | elif not force and different: |
|
523 | elif not force and different: | |
541 | aborts.append((f, "ud")) |
|
524 | aborts.append((f, "ud")) | |
542 | else: |
|
525 | else: | |
543 |
actions.append((f |
|
526 | actions['g'].append((f, (fl2,), "remote created")) | |
544 | elif n2 and n2 != ma[f]: |
|
527 | elif n2 and n2 != ma[f]: | |
545 | different = _checkunknownfile(repo, wctx, p2, f) |
|
528 | different = _checkunknownfile(repo, wctx, p2, f) | |
546 | if not force and different: |
|
529 | if not force and different: | |
@@ -548,10 +531,10 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
548 | else: |
|
531 | else: | |
549 | # if different: old untracked f may be overwritten and lost |
|
532 | # if different: old untracked f may be overwritten and lost | |
550 | if acceptremote: |
|
533 | if acceptremote: | |
551 |
actions.append((f |
|
534 | actions['g'].append((f, (m2.flags(f),), | |
552 | "remote recreating")) |
|
535 | "remote recreating")) | |
553 | else: |
|
536 | else: | |
554 |
actions.append((f |
|
537 | actions['dc'].append((f, (m2.flags(f),), | |
555 | "prompt deleted/changed")) |
|
538 | "prompt deleted/changed")) | |
556 |
|
539 | |||
557 | for f, m in sorted(aborts): |
|
540 | for f, m in sorted(aborts): | |
@@ -566,18 +549,12 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
566 | # check collision between files only in p2 for clean update |
|
549 | # check collision between files only in p2 for clean update | |
567 | if (not branchmerge and |
|
550 | if (not branchmerge and | |
568 | (force or not wctx.dirty(missing=True, branch=False))): |
|
551 | (force or not wctx.dirty(missing=True, branch=False))): | |
569 |
_checkcollision(repo, m2, |
|
552 | _checkcollision(repo, m2, None) | |
570 | else: |
|
553 | else: | |
571 | _checkcollision(repo, m1, actions) |
|
554 | _checkcollision(repo, m1, actions) | |
572 |
|
555 | |||
573 | return actions |
|
556 | return actions | |
574 |
|
557 | |||
575 | actionpriority = dict((m, p) for p, m in enumerate( |
|
|||
576 | ['r', 'f', 'g', 'a', 'k', 'm', 'dm', 'dg', 'dr', 'cd', 'dc', 'rd', 'e'])) |
|
|||
577 |
|
||||
578 | def actionkey(a): |
|
|||
579 | return actionpriority[a[1]], a |
|
|||
580 |
|
||||
581 | def batchremove(repo, actions): |
|
558 | def batchremove(repo, actions): | |
582 | """apply removes to the working directory |
|
559 | """apply removes to the working directory | |
583 |
|
560 | |||
@@ -588,7 +565,7 b' def batchremove(repo, actions):' | |||||
588 | wjoin = repo.wjoin |
|
565 | wjoin = repo.wjoin | |
589 | audit = repo.wopener.audit |
|
566 | audit = repo.wopener.audit | |
590 | i = 0 |
|
567 | i = 0 | |
591 |
for f |
|
568 | for f, args, msg in actions: | |
592 | repo.ui.debug(" %s: %s -> r\n" % (f, msg)) |
|
569 | repo.ui.debug(" %s: %s -> r\n" % (f, msg)) | |
593 | if True: |
|
570 | if True: | |
594 | if verbose: |
|
571 | if verbose: | |
@@ -617,7 +594,7 b' def batchget(repo, mctx, actions):' | |||||
617 | fctx = mctx.filectx |
|
594 | fctx = mctx.filectx | |
618 | wwrite = repo.wwrite |
|
595 | wwrite = repo.wwrite | |
619 | i = 0 |
|
596 | i = 0 | |
620 |
for f |
|
597 | for f, args, msg in actions: | |
621 | repo.ui.debug(" %s: %s -> g\n" % (f, msg)) |
|
598 | repo.ui.debug(" %s: %s -> g\n" % (f, msg)) | |
622 | if True: |
|
599 | if True: | |
623 | if verbose: |
|
600 | if verbose: | |
@@ -644,12 +621,12 b' def applyupdates(repo, actions, wctx, mc' | |||||
644 | ms = mergestate(repo) |
|
621 | ms = mergestate(repo) | |
645 | ms.reset(wctx.p1().node(), mctx.node()) |
|
622 | ms.reset(wctx.p1().node(), mctx.node()) | |
646 | moves = [] |
|
623 | moves = [] | |
647 | actions.sort(key=actionkey) |
|
624 | for m, l in actions.items(): | |
|
625 | l.sort() | |||
648 |
|
626 | |||
649 | # prescan for merges |
|
627 | # prescan for merges | |
650 | for a in actions: |
|
628 | for f, args, msg in actions['m']: | |
651 | f, m, args, msg = a |
|
629 | if True: | |
652 | if m == "m": # merge |
|
|||
653 | f1, f2, fa, move, anc = args |
|
630 | f1, f2, fa, move, anc = args | |
654 | if f == '.hgsubstate': # merged internally |
|
631 | if f == '.hgsubstate': # merged internally | |
655 | continue |
|
632 | continue | |
@@ -677,55 +654,50 b' def applyupdates(repo, actions, wctx, mc' | |||||
677 | audit(f) |
|
654 | audit(f) | |
678 | util.unlinkpath(repo.wjoin(f)) |
|
655 | util.unlinkpath(repo.wjoin(f)) | |
679 |
|
656 | |||
680 |
numupdates = len( |
|
657 | numupdates = sum(len(l) for m, l in actions.items() if m != 'k') | |
681 | workeractions = [a for a in actions if a[1] in 'gr'] |
|
|||
682 | updateactions = [a for a in workeractions if a[1] == 'g'] |
|
|||
683 | updated = len(updateactions) |
|
|||
684 | removeactions = [a for a in workeractions if a[1] == 'r'] |
|
|||
685 | removed = len(removeactions) |
|
|||
686 | actions = [a for a in actions if a[1] not in 'gr'] |
|
|||
687 |
|
658 | |||
688 |
|
|
659 | if [a for a in actions['r'] if a[0] == '.hgsubstate']: | |
689 | if hgsub and hgsub[0] == 'r': |
|
|||
690 | subrepo.submerge(repo, wctx, mctx, wctx, overwrite) |
|
660 | subrepo.submerge(repo, wctx, mctx, wctx, overwrite) | |
691 |
|
661 | |||
692 | # remove in parallel (must come first) |
|
662 | # remove in parallel (must come first) | |
693 | z = 0 |
|
663 | z = 0 | |
694 |
prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), |
|
664 | prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r']) | |
695 | for i, item in prog: |
|
665 | for i, item in prog: | |
696 | z += i |
|
666 | z += i | |
697 | progress(_updating, z, item=item, total=numupdates, unit=_files) |
|
667 | progress(_updating, z, item=item, total=numupdates, unit=_files) | |
|
668 | removed = len(actions['r']) | |||
698 |
|
669 | |||
699 | # get in parallel |
|
670 | # get in parallel | |
700 |
prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), |
|
671 | prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g']) | |
701 | for i, item in prog: |
|
672 | for i, item in prog: | |
702 | z += i |
|
673 | z += i | |
703 | progress(_updating, z, item=item, total=numupdates, unit=_files) |
|
674 | progress(_updating, z, item=item, total=numupdates, unit=_files) | |
|
675 | updated = len(actions['g']) | |||
704 |
|
676 | |||
705 | if hgsub and hgsub[0] == 'g': |
|
677 | if [a for a in actions['g'] if a[0] == '.hgsubstate']: | |
706 | subrepo.submerge(repo, wctx, mctx, wctx, overwrite) |
|
678 | subrepo.submerge(repo, wctx, mctx, wctx, overwrite) | |
707 |
|
679 | |||
708 | for f, m, args, msg in actions: |
|
680 | if True: | |
709 |
|
681 | |||
710 | # forget (manifest only, just log it) (must come first) |
|
682 | # forget (manifest only, just log it) (must come first) | |
711 | if m == "f": |
|
683 | for f, args, msg in actions['f']: | |
712 | repo.ui.debug(" %s: %s -> f\n" % (f, msg)) |
|
684 | repo.ui.debug(" %s: %s -> f\n" % (f, msg)) | |
713 | z += 1 |
|
685 | z += 1 | |
714 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
686 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
715 |
|
687 | |||
716 | # re-add (manifest only, just log it) |
|
688 | # re-add (manifest only, just log it) | |
717 | elif m == "a": |
|
689 | for f, args, msg in actions['a']: | |
718 | repo.ui.debug(" %s: %s -> a\n" % (f, msg)) |
|
690 | repo.ui.debug(" %s: %s -> a\n" % (f, msg)) | |
719 | z += 1 |
|
691 | z += 1 | |
720 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
692 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
721 |
|
693 | |||
722 | # keep (noop, just log it) |
|
694 | # keep (noop, just log it) | |
723 | elif m == "k": |
|
695 | for f, args, msg in actions['k']: | |
724 | repo.ui.debug(" %s: %s -> k\n" % (f, msg)) |
|
696 | repo.ui.debug(" %s: %s -> k\n" % (f, msg)) | |
725 | # no progress |
|
697 | # no progress | |
726 |
|
698 | |||
727 | # merge |
|
699 | # merge | |
728 | elif m == "m": |
|
700 | for f, args, msg in actions['m']: | |
729 | repo.ui.debug(" %s: %s -> m\n" % (f, msg)) |
|
701 | repo.ui.debug(" %s: %s -> m\n" % (f, msg)) | |
730 | z += 1 |
|
702 | z += 1 | |
731 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
703 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -745,7 +717,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
745 | merged += 1 |
|
717 | merged += 1 | |
746 |
|
718 | |||
747 | # directory rename, move local |
|
719 | # directory rename, move local | |
748 | elif m == "dm": |
|
720 | for f, args, msg in actions['dm']: | |
749 | repo.ui.debug(" %s: %s -> dm\n" % (f, msg)) |
|
721 | repo.ui.debug(" %s: %s -> dm\n" % (f, msg)) | |
750 | z += 1 |
|
722 | z += 1 | |
751 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
723 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -757,7 +729,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
757 | updated += 1 |
|
729 | updated += 1 | |
758 |
|
730 | |||
759 | # local directory rename, get |
|
731 | # local directory rename, get | |
760 | elif m == "dg": |
|
732 | for f, args, msg in actions['dg']: | |
761 | repo.ui.debug(" %s: %s -> dg\n" % (f, msg)) |
|
733 | repo.ui.debug(" %s: %s -> dg\n" % (f, msg)) | |
762 | z += 1 |
|
734 | z += 1 | |
763 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
735 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -767,7 +739,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
767 | updated += 1 |
|
739 | updated += 1 | |
768 |
|
740 | |||
769 | # divergent renames |
|
741 | # divergent renames | |
770 | elif m == "dr": |
|
742 | for f, args, msg in actions['dr']: | |
771 | repo.ui.debug(" %s: %s -> dr\n" % (f, msg)) |
|
743 | repo.ui.debug(" %s: %s -> dr\n" % (f, msg)) | |
772 | z += 1 |
|
744 | z += 1 | |
773 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
745 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -778,7 +750,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
778 | repo.ui.warn(" %s\n" % nf) |
|
750 | repo.ui.warn(" %s\n" % nf) | |
779 |
|
751 | |||
780 | # rename and delete |
|
752 | # rename and delete | |
781 | elif m == "rd": |
|
753 | for f, args, msg in actions['rd']: | |
782 | repo.ui.debug(" %s: %s -> rd\n" % (f, msg)) |
|
754 | repo.ui.debug(" %s: %s -> rd\n" % (f, msg)) | |
783 | z += 1 |
|
755 | z += 1 | |
784 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
756 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -789,7 +761,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
789 | repo.ui.warn(" %s\n" % nf) |
|
761 | repo.ui.warn(" %s\n" % nf) | |
790 |
|
762 | |||
791 | # exec |
|
763 | # exec | |
792 | elif m == "e": |
|
764 | for f, args, msg in actions['e']: | |
793 | repo.ui.debug(" %s: %s -> e\n" % (f, msg)) |
|
765 | repo.ui.debug(" %s: %s -> e\n" % (f, msg)) | |
794 | z += 1 |
|
766 | z += 1 | |
795 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
767 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -818,132 +790,127 b' def calculateupdates(repo, wctx, mctx, a' | |||||
818 | (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors))) |
|
790 | (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors))) | |
819 |
|
791 | |||
820 | # Call for bids |
|
792 | # Call for bids | |
821 |
fbids = {} # mapping filename to list af action |
|
793 | fbids = {} # mapping filename to bids (action method to list af actions) | |
822 | for ancestor in ancestors: |
|
794 | for ancestor in ancestors: | |
823 | repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor) |
|
795 | repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor) | |
824 | actions = manifestmerge(repo, wctx, mctx, ancestor, |
|
796 | actions = manifestmerge(repo, wctx, mctx, ancestor, | |
825 | branchmerge, force, |
|
797 | branchmerge, force, | |
826 | partial, acceptremote, followcopies) |
|
798 | partial, acceptremote, followcopies) | |
827 |
for |
|
799 | for m, l in sorted(actions.items()): | |
828 |
f |
|
800 | for a in l: | |
|
801 | f, args, msg = a | |||
829 | repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m)) |
|
802 | repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m)) | |
830 | if f in fbids: |
|
803 | if f in fbids: | |
831 |
fbids[f] |
|
804 | d = fbids[f] | |
|
805 | if m in d: | |||
|
806 | d[m].append(a) | |||
832 | else: |
|
807 | else: | |
833 |
|
|
808 | d[m] = [a] | |
|
809 | else: | |||
|
810 | fbids[f] = {m: [a]} | |||
834 |
|
811 | |||
835 | # Pick the best bid for each file |
|
812 | # Pick the best bid for each file | |
836 | repo.ui.note(_('\nauction for merging merge bids\n')) |
|
813 | repo.ui.note(_('\nauction for merging merge bids\n')) | |
837 | actions = [] |
|
814 | actions = dict((m, []) for m in actions.keys()) | |
838 |
for f, bids |
|
815 | for f, bids in sorted(fbids.items()): | |
|
816 | # bids is a mapping from action method to list af actions | |||
839 | # Consensus? |
|
817 | # Consensus? | |
840 | a0 = bidsl[0] |
|
818 | if len(bids) == 1: # all bids are the same kind of method | |
841 | if util.all(a == a0 for a in bidsl[1:]): # len(bidsl) is > 1 |
|
819 | m, l = bids.items()[0] | |
842 | repo.ui.note(" %s: consensus for %s\n" % (f, a0[1])) |
|
820 | if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1 | |
843 | actions.append(a0) |
|
821 | repo.ui.note(" %s: consensus for %s\n" % (f, m)) | |
|
822 | actions[m].append(l[0]) | |||
844 | continue |
|
823 | continue | |
845 | # Group bids by kind of action |
|
|||
846 | bids = {} |
|
|||
847 | for a in bidsl: |
|
|||
848 | m = a[1] |
|
|||
849 | if m in bids: |
|
|||
850 | bids[m].append(a) |
|
|||
851 | else: |
|
|||
852 | bids[m] = [a] |
|
|||
853 | # If keep is an option, just do it. |
|
824 | # If keep is an option, just do it. | |
854 | if "k" in bids: |
|
825 | if "k" in bids: | |
855 | repo.ui.note(" %s: picking 'keep' action\n" % f) |
|
826 | repo.ui.note(" %s: picking 'keep' action\n" % f) | |
856 | actions.append(bids["k"][0]) |
|
827 | actions['k'].append(bids["k"][0]) | |
857 | continue |
|
828 | continue | |
858 |
# If |
|
829 | # If there are gets and they all agree [how could they not?], do it. | |
859 | if "g" in bids: |
|
830 | if "g" in bids: | |
860 | ga0 = bids["g"][0] |
|
831 | ga0 = bids["g"][0] | |
861 | if util.all(a == ga0 for a in bids["g"][1:]): |
|
832 | if util.all(a == ga0 for a in bids["g"][1:]): | |
862 | repo.ui.note(" %s: picking 'get' action\n" % f) |
|
833 | repo.ui.note(" %s: picking 'get' action\n" % f) | |
863 | actions.append(ga0) |
|
834 | actions['g'].append(ga0) | |
864 | continue |
|
835 | continue | |
865 | # TODO: Consider other simple actions such as mode changes |
|
836 | # TODO: Consider other simple actions such as mode changes | |
866 | # Handle inefficient democrazy. |
|
837 | # Handle inefficient democrazy. | |
867 | repo.ui.note(_(' %s: multiple bids for merge action:\n') % f) |
|
838 | repo.ui.note(_(' %s: multiple bids for merge action:\n') % f) | |
868 |
for |
|
839 | for m, l in sorted(bids.items()): | |
|
840 | for _f, args, msg in l: | |||
869 | repo.ui.note(' %s -> %s\n' % (msg, m)) |
|
841 | repo.ui.note(' %s -> %s\n' % (msg, m)) | |
870 | # Pick random action. TODO: Instead, prompt user when resolving |
|
842 | # Pick random action. TODO: Instead, prompt user when resolving | |
871 |
|
|
843 | m, l = bids.items()[0] | |
872 | repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % |
|
844 | repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % | |
873 |
(f, |
|
845 | (f, m)) | |
874 |
actions.append( |
|
846 | actions[m].append(l[0]) | |
875 | continue |
|
847 | continue | |
876 | repo.ui.note(_('end of auction\n\n')) |
|
848 | repo.ui.note(_('end of auction\n\n')) | |
877 |
|
849 | |||
878 | # Filter out prompts. |
|
|||
879 | newactions, prompts = [], [] |
|
|||
880 | for a in actions: |
|
|||
881 | if a[1] in ("cd", "dc"): |
|
|||
882 | prompts.append(a) |
|
|||
883 | else: |
|
|||
884 | newactions.append(a) |
|
|||
885 | # Prompt and create actions. TODO: Move this towards resolve phase. |
|
850 | # Prompt and create actions. TODO: Move this towards resolve phase. | |
886 | for f, m, args, msg in sorted(prompts): |
|
851 | if True: | |
887 | if m == "cd": |
|
852 | for f, args, msg in actions['cd']: | |
888 | if repo.ui.promptchoice( |
|
853 | if repo.ui.promptchoice( | |
889 | _("local changed %s which remote deleted\n" |
|
854 | _("local changed %s which remote deleted\n" | |
890 | "use (c)hanged version or (d)elete?" |
|
855 | "use (c)hanged version or (d)elete?" | |
891 | "$$ &Changed $$ &Delete") % f, 0): |
|
856 | "$$ &Changed $$ &Delete") % f, 0): | |
892 |
|
|
857 | actions['r'].append((f, None, "prompt delete")) | |
893 | else: |
|
858 | else: | |
894 |
|
|
859 | actions['a'].append((f, None, "prompt keep")) | |
895 | elif m == "dc": |
|
860 | del actions['cd'][:] | |
|
861 | ||||
|
862 | for f, args, msg in actions['dc']: | |||
896 | flags, = args |
|
863 | flags, = args | |
897 | if repo.ui.promptchoice( |
|
864 | if repo.ui.promptchoice( | |
898 | _("remote changed %s which local deleted\n" |
|
865 | _("remote changed %s which local deleted\n" | |
899 | "use (c)hanged version or leave (d)eleted?" |
|
866 | "use (c)hanged version or leave (d)eleted?" | |
900 | "$$ &Changed $$ &Deleted") % f, 0) == 0: |
|
867 | "$$ &Changed $$ &Deleted") % f, 0) == 0: | |
901 |
|
|
868 | actions['g'].append((f, (flags,), "prompt recreating")) | |
902 | else: assert False, m |
|
869 | del actions['dc'][:] | |
903 |
|
870 | |||
904 | if wctx.rev() is None: |
|
871 | if wctx.rev() is None: | |
905 |
|
|
872 | ractions, factions = _forgetremoved(wctx, mctx, branchmerge) | |
|
873 | actions['r'].extend(ractions) | |||
|
874 | actions['f'].extend(factions) | |||
906 |
|
875 | |||
907 |
return |
|
876 | return actions | |
908 |
|
877 | |||
909 | def recordupdates(repo, actions, branchmerge): |
|
878 | def recordupdates(repo, actions, branchmerge): | |
910 | "record merge actions to the dirstate" |
|
879 | "record merge actions to the dirstate" | |
911 |
|
880 | if True: | ||
912 | for f, m, args, msg in actions: |
|
|||
913 |
|
||||
914 | # remove (must come first) |
|
881 | # remove (must come first) | |
915 | if m == "r": # remove |
|
882 | for f, args, msg in actions['r']: | |
916 | if branchmerge: |
|
883 | if branchmerge: | |
917 | repo.dirstate.remove(f) |
|
884 | repo.dirstate.remove(f) | |
918 | else: |
|
885 | else: | |
919 | repo.dirstate.drop(f) |
|
886 | repo.dirstate.drop(f) | |
920 |
|
887 | |||
921 | # forget (must come first) |
|
888 | # forget (must come first) | |
922 | elif m == "f": |
|
889 | for f, args, msg in actions['f']: | |
923 | repo.dirstate.drop(f) |
|
890 | repo.dirstate.drop(f) | |
924 |
|
891 | |||
925 | # re-add |
|
892 | # re-add | |
926 | elif m == "a": |
|
893 | for f, args, msg in actions['a']: | |
927 | if not branchmerge: |
|
894 | if not branchmerge: | |
928 | repo.dirstate.add(f) |
|
895 | repo.dirstate.add(f) | |
929 |
|
896 | |||
930 | # exec change |
|
897 | # exec change | |
931 | elif m == "e": |
|
898 | for f, args, msg in actions['e']: | |
932 | repo.dirstate.normallookup(f) |
|
899 | repo.dirstate.normallookup(f) | |
933 |
|
900 | |||
934 | # keep |
|
901 | # keep | |
935 | elif m == "k": |
|
902 | for f, args, msg in actions['k']: | |
936 | pass |
|
903 | pass | |
937 |
|
904 | |||
938 | # get |
|
905 | # get | |
939 | elif m == "g": |
|
906 | for f, args, msg in actions['g']: | |
940 | if branchmerge: |
|
907 | if branchmerge: | |
941 | repo.dirstate.otherparent(f) |
|
908 | repo.dirstate.otherparent(f) | |
942 | else: |
|
909 | else: | |
943 | repo.dirstate.normal(f) |
|
910 | repo.dirstate.normal(f) | |
944 |
|
911 | |||
945 | # merge |
|
912 | # merge | |
946 | elif m == "m": |
|
913 | for f, args, msg in actions['m']: | |
947 | f1, f2, fa, move, anc = args |
|
914 | f1, f2, fa, move, anc = args | |
948 | if branchmerge: |
|
915 | if branchmerge: | |
949 | # We've done a branch merge, mark this file as merged |
|
916 | # We've done a branch merge, mark this file as merged | |
@@ -968,7 +935,7 b' def recordupdates(repo, actions, branchm' | |||||
968 | repo.dirstate.drop(f1) |
|
935 | repo.dirstate.drop(f1) | |
969 |
|
936 | |||
970 | # directory rename, move local |
|
937 | # directory rename, move local | |
971 | elif m == "dm": |
|
938 | for f, args, msg in actions['dm']: | |
972 | f0, flag = args |
|
939 | f0, flag = args | |
973 | if f0 not in repo.dirstate: |
|
940 | if f0 not in repo.dirstate: | |
974 | # untracked file moved |
|
941 | # untracked file moved | |
@@ -982,7 +949,7 b' def recordupdates(repo, actions, branchm' | |||||
982 | repo.dirstate.drop(f0) |
|
949 | repo.dirstate.drop(f0) | |
983 |
|
950 | |||
984 | # directory rename, get |
|
951 | # directory rename, get | |
985 | elif m == "dg": |
|
952 | for f, args, msg in actions['dg']: | |
986 | f0, flag = args |
|
953 | f0, flag = args | |
987 | if branchmerge: |
|
954 | if branchmerge: | |
988 | repo.dirstate.add(f) |
|
955 | repo.dirstate.add(f) |
General Comments 0
You need to be logged in to leave comments.
Login now