510 |
512 |
511 for a in action: |
513 for a in action: |
512 f, m = a[:2] |
514 f, m = a[:2] |
513 if m == "r": # remove |
515 if m == "r": # remove |
514 if branchmerge: |
516 if branchmerge: |
515 repo.dirstate.update([f], 'r') |
517 repo.dirstate.remove(f) |
516 else: |
518 else: |
517 repo.dirstate.forget([f]) |
519 repo.dirstate.forget(f) |
518 elif m == "f": # forget |
520 elif m == "f": # forget |
519 repo.dirstate.forget([f]) |
521 repo.dirstate.forget(f) |
520 elif m in "ge": # get or exec change |
522 elif m in "ge": # get or exec change |
521 if branchmerge: |
523 if branchmerge: |
522 repo.dirstate.update([f], 'n', st_mtime=-1) |
524 repo.dirstate.normaldirty(f) |
523 else: |
525 else: |
524 repo.dirstate.update([f], 'n') |
526 repo.dirstate.normal(f) |
525 elif m == "m": # merge |
527 elif m == "m": # merge |
526 f2, fd, flag, move = a[2:] |
528 f2, fd, flag, move = a[2:] |
527 if branchmerge: |
529 if branchmerge: |
528 # We've done a branch merge, mark this file as merged |
530 # We've done a branch merge, mark this file as merged |
529 # so that we properly record the merger later |
531 # so that we properly record the merger later |
530 repo.dirstate.update([fd], 'm') |
532 repo.dirstate.merge(fd) |
531 if f != f2: # copy/rename |
533 if f != f2: # copy/rename |
532 if move: |
534 if move: |
533 repo.dirstate.update([f], 'r') |
535 repo.dirstate.remove(f) |
534 if f != fd: |
536 if f != fd: |
535 repo.dirstate.copy(f, fd) |
537 repo.dirstate.copy(f, fd) |
536 else: |
538 else: |
537 repo.dirstate.copy(f2, fd) |
539 repo.dirstate.copy(f2, fd) |
538 else: |
540 else: |
539 # We've update-merged a locally modified file, so |
541 # We've update-merged a locally modified file, so |
540 # we set the dirstate to emulate a normal checkout |
542 # we set the dirstate to emulate a normal checkout |
541 # of that file some time in the past. Thus our |
543 # of that file some time in the past. Thus our |
542 # merge will appear as a normal local file |
544 # merge will appear as a normal local file |
543 # modification. |
545 # modification. |
544 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1) |
546 repo.dirstate.normallookup(fd) |
545 if move: |
547 if move: |
546 repo.dirstate.forget([f]) |
548 repo.dirstate.forget(f) |
547 elif m == "d": # directory rename |
549 elif m == "d": # directory rename |
548 f2, fd, flag = a[2:] |
550 f2, fd, flag = a[2:] |
549 if not f2 and f not in repo.dirstate: |
551 if not f2 and f not in repo.dirstate: |
550 # untracked file moved |
552 # untracked file moved |
551 continue |
553 continue |
552 if branchmerge: |
554 if branchmerge: |
553 repo.dirstate.update([fd], 'a') |
555 repo.dirstate.add(fd) |
554 if f: |
556 if f: |
555 repo.dirstate.update([f], 'r') |
557 repo.dirstate.remove(f) |
556 repo.dirstate.copy(f, fd) |
558 repo.dirstate.copy(f, fd) |
557 if f2: |
559 if f2: |
558 repo.dirstate.copy(f2, fd) |
560 repo.dirstate.copy(f2, fd) |
559 else: |
561 else: |
560 repo.dirstate.update([fd], 'n') |
562 repo.dirstate.normal(fd) |
561 if f: |
563 if f: |
562 repo.dirstate.forget([f]) |
564 repo.dirstate.forget(f) |
563 |
565 |
564 def update(repo, node, branchmerge, force, partial, wlock): |
566 def update(repo, node, branchmerge, force, partial): |
565 """ |
567 """ |
566 Perform a merge between the working directory and the given node |
568 Perform a merge between the working directory and the given node |
567 |
569 |
568 branchmerge = whether to merge between branches |
570 branchmerge = whether to merge between branches |
569 force = whether to force branch merging or file overwriting |
571 force = whether to force branch merging or file overwriting |
570 partial = a function to filter file lists (dirstate not updated) |
572 partial = a function to filter file lists (dirstate not updated) |
571 wlock = working dir lock, if already held |
573 """ |
572 """ |
574 |
573 |
575 wlock = repo.wlock() |
574 if not wlock: |
576 try: |
575 wlock = repo.wlock() |
577 wc = repo.workingctx() |
576 |
578 if node is None: |
577 wc = repo.workingctx() |
579 # tip of current branch |
578 if node is None: |
580 try: |
579 # tip of current branch |
581 node = repo.branchtags()[wc.branch()] |
580 try: |
582 except KeyError: |
581 node = repo.branchtags()[wc.branch()] |
583 raise util.Abort(_("branch %s not found") % wc.branch()) |
582 except KeyError: |
584 overwrite = force and not branchmerge |
583 raise util.Abort(_("branch %s not found") % wc.branch()) |
585 forcemerge = force and branchmerge |
584 overwrite = force and not branchmerge |
586 pl = wc.parents() |
585 forcemerge = force and branchmerge |
587 p1, p2 = pl[0], repo.changectx(node) |
586 pl = wc.parents() |
588 pa = p1.ancestor(p2) |
587 p1, p2 = pl[0], repo.changectx(node) |
589 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
588 pa = p1.ancestor(p2) |
590 fastforward = False |
589 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
591 |
590 fastforward = False |
592 ### check phase |
591 |
593 if not overwrite and len(pl) > 1: |
592 ### check phase |
594 raise util.Abort(_("outstanding uncommitted merges")) |
593 if not overwrite and len(pl) > 1: |
595 if pa == p1 or pa == p2: # is there a linear path from p1 to p2? |
594 raise util.Abort(_("outstanding uncommitted merges")) |
596 if branchmerge: |
595 if pa == p1 or pa == p2: # is there a linear path from p1 to p2? |
597 if p1.branch() != p2.branch() and pa != p2: |
596 if branchmerge: |
598 fastforward = True |
597 if p1.branch() != p2.branch() and pa != p2: |
599 else: |
598 fastforward = True |
600 raise util.Abort(_("there is nothing to merge, just use " |
599 else: |
601 "'hg update' or look at 'hg heads'")) |
600 raise util.Abort(_("there is nothing to merge, just use " |
602 elif not (overwrite or branchmerge): |
601 "'hg update' or look at 'hg heads'")) |
603 raise util.Abort(_("update spans branches, use 'hg merge' " |
602 elif not (overwrite or branchmerge): |
604 "or 'hg update -C' to lose changes")) |
603 raise util.Abort(_("update spans branches, use 'hg merge' " |
605 if branchmerge and not forcemerge: |
604 "or 'hg update -C' to lose changes")) |
606 if wc.files(): |
605 if branchmerge and not forcemerge: |
607 raise util.Abort(_("outstanding uncommitted changes")) |
606 if wc.files(): |
608 |
607 raise util.Abort(_("outstanding uncommitted changes")) |
609 ### calculate phase |
608 |
610 action = [] |
609 ### calculate phase |
611 if not force: |
610 action = [] |
612 checkunknown(wc, p2) |
611 if not force: |
613 if not util.checkfolding(repo.path): |
612 checkunknown(wc, p2) |
614 checkcollision(p2) |
613 if not util.checkfolding(repo.path): |
615 if not branchmerge: |
614 checkcollision(p2) |
616 action += forgetremoved(wc, p2) |
615 if not branchmerge: |
617 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
616 action += forgetremoved(wc, p2) |
618 |
617 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
619 ### apply phase |
618 |
620 if not branchmerge: # just jump to the new rev |
619 ### apply phase |
621 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
620 if not branchmerge: # just jump to the new rev |
622 if not partial: |
621 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
623 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
622 if not partial: |
624 |
623 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
625 stats = applyupdates(repo, action, wc, p2) |
624 |
626 |
625 stats = applyupdates(repo, action, wc, p2) |
627 if not partial: |
626 |
628 recordupdates(repo, action, branchmerge) |
627 if not partial: |
629 repo.dirstate.setparents(fp1, fp2) |
628 recordupdates(repo, action, branchmerge) |
630 if not branchmerge and not fastforward: |
629 repo.dirstate.setparents(fp1, fp2) |
631 repo.dirstate.setbranch(p2.branch()) |
630 if not branchmerge and not fastforward: |
632 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3]) |
631 repo.dirstate.setbranch(p2.branch()) |
633 |
632 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3]) |
634 return stats |
633 |
635 finally: |
634 return stats |
636 del wlock |
635 |
|