453 |
453 |
454 for a in action: |
454 for a in action: |
455 f, m = a[:2] |
455 f, m = a[:2] |
456 if m == "r": # remove |
456 if m == "r": # remove |
457 if branchmerge: |
457 if branchmerge: |
458 repo.dirstate.update([f], 'r') |
458 repo.dirstate.remove(f) |
459 else: |
459 else: |
460 repo.dirstate.forget([f]) |
460 repo.dirstate.forget(f) |
461 elif m == "f": # forget |
461 elif m == "f": # forget |
462 repo.dirstate.forget([f]) |
462 repo.dirstate.forget(f) |
463 elif m in "ge": # get or exec change |
463 elif m in "ge": # get or exec change |
464 if branchmerge: |
464 if branchmerge: |
465 repo.dirstate.update([f], 'n', st_mtime=-1) |
465 repo.dirstate.normaldirty(f) |
466 else: |
466 else: |
467 repo.dirstate.update([f], 'n') |
467 repo.dirstate.normal(f) |
468 elif m == "m": # merge |
468 elif m == "m": # merge |
469 f2, fd, flag, move = a[2:] |
469 f2, fd, flag, move = a[2:] |
470 if branchmerge: |
470 if branchmerge: |
471 # We've done a branch merge, mark this file as merged |
471 # We've done a branch merge, mark this file as merged |
472 # so that we properly record the merger later |
472 # so that we properly record the merger later |
473 repo.dirstate.update([fd], 'm') |
473 repo.dirstate.merge(fd) |
474 if f != f2: # copy/rename |
474 if f != f2: # copy/rename |
475 if move: |
475 if move: |
476 repo.dirstate.update([f], 'r') |
476 repo.dirstate.remove(f) |
477 if f != fd: |
477 if f != fd: |
478 repo.dirstate.copy(f, fd) |
478 repo.dirstate.copy(f, fd) |
479 else: |
479 else: |
480 repo.dirstate.copy(f2, fd) |
480 repo.dirstate.copy(f2, fd) |
481 else: |
481 else: |
482 # We've update-merged a locally modified file, so |
482 # We've update-merged a locally modified file, so |
483 # we set the dirstate to emulate a normal checkout |
483 # we set the dirstate to emulate a normal checkout |
484 # of that file some time in the past. Thus our |
484 # of that file some time in the past. Thus our |
485 # merge will appear as a normal local file |
485 # merge will appear as a normal local file |
486 # modification. |
486 # modification. |
487 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1) |
487 repo.dirstate.normaldirty(fd) |
488 if move: |
488 if move: |
489 repo.dirstate.forget([f]) |
489 repo.dirstate.forget(f) |
490 elif m == "d": # directory rename |
490 elif m == "d": # directory rename |
491 f2, fd, flag = a[2:] |
491 f2, fd, flag = a[2:] |
492 if not f2 and f not in repo.dirstate: |
492 if not f2 and f not in repo.dirstate: |
493 # untracked file moved |
493 # untracked file moved |
494 continue |
494 continue |
495 if branchmerge: |
495 if branchmerge: |
496 repo.dirstate.update([fd], 'a') |
496 repo.dirstate.add(fd) |
497 if f: |
497 if f: |
498 repo.dirstate.update([f], 'r') |
498 repo.dirstate.remove(f) |
499 repo.dirstate.copy(f, fd) |
499 repo.dirstate.copy(f, fd) |
500 if f2: |
500 if f2: |
501 repo.dirstate.copy(f2, fd) |
501 repo.dirstate.copy(f2, fd) |
502 else: |
502 else: |
503 repo.dirstate.update([fd], 'n') |
503 repo.dirstate.normal(fd) |
504 if f: |
504 if f: |
505 repo.dirstate.forget([f]) |
505 repo.dirstate.forget(f) |
506 |
506 |
507 def update(repo, node, branchmerge, force, partial, wlock): |
507 def update(repo, node, branchmerge, force, partial): |
508 """ |
508 """ |
509 Perform a merge between the working directory and the given node |
509 Perform a merge between the working directory and the given node |
510 |
510 |
511 branchmerge = whether to merge between branches |
511 branchmerge = whether to merge between branches |
512 force = whether to force branch merging or file overwriting |
512 force = whether to force branch merging or file overwriting |
513 partial = a function to filter file lists (dirstate not updated) |
513 partial = a function to filter file lists (dirstate not updated) |
514 wlock = working dir lock, if already held |
514 """ |
515 """ |
515 |
516 |
516 wlock = repo.wlock() |
517 if not wlock: |
517 try: |
518 wlock = repo.wlock() |
518 wc = repo.workingctx() |
519 |
519 if node is None: |
520 wc = repo.workingctx() |
520 # tip of current branch |
521 if node is None: |
521 try: |
522 # tip of current branch |
522 node = repo.branchtags()[wc.branch()] |
523 try: |
523 except KeyError: |
524 node = repo.branchtags()[wc.branch()] |
524 raise util.Abort(_("branch %s not found") % wc.branch()) |
525 except KeyError: |
525 overwrite = force and not branchmerge |
526 raise util.Abort(_("branch %s not found") % wc.branch()) |
526 forcemerge = force and branchmerge |
527 overwrite = force and not branchmerge |
527 pl = wc.parents() |
528 forcemerge = force and branchmerge |
528 p1, p2 = pl[0], repo.changectx(node) |
529 pl = wc.parents() |
529 pa = p1.ancestor(p2) |
530 p1, p2 = pl[0], repo.changectx(node) |
530 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
531 pa = p1.ancestor(p2) |
531 fastforward = False |
532 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
532 |
533 fastforward = False |
533 ### check phase |
534 |
534 if not overwrite and len(pl) > 1: |
535 ### check phase |
535 raise util.Abort(_("outstanding uncommitted merges")) |
536 if not overwrite and len(pl) > 1: |
536 if pa == p1 or pa == p2: # is there a linear path from p1 to p2? |
537 raise util.Abort(_("outstanding uncommitted merges")) |
537 if branchmerge: |
538 if pa == p1 or pa == p2: # is there a linear path from p1 to p2? |
538 if p1.branch() != p2.branch() and pa != p2: |
539 if branchmerge: |
539 fastforward = True |
540 if p1.branch() != p2.branch() and pa != p2: |
540 else: |
541 fastforward = True |
541 raise util.Abort(_("there is nothing to merge, just use " |
542 else: |
542 "'hg update' or look at 'hg heads'")) |
543 raise util.Abort(_("there is nothing to merge, just use " |
543 elif not (overwrite or branchmerge): |
544 "'hg update' or look at 'hg heads'")) |
544 raise util.Abort(_("update spans branches, use 'hg merge' " |
545 elif not (overwrite or branchmerge): |
545 "or 'hg update -C' to lose changes")) |
546 raise util.Abort(_("update spans branches, use 'hg merge' " |
546 if branchmerge and not forcemerge: |
547 "or 'hg update -C' to lose changes")) |
547 if wc.files(): |
548 if branchmerge and not forcemerge: |
548 raise util.Abort(_("outstanding uncommitted changes")) |
549 if wc.files(): |
549 |
550 raise util.Abort(_("outstanding uncommitted changes")) |
550 ### calculate phase |
551 |
551 action = [] |
552 ### calculate phase |
552 if not force: |
553 action = [] |
553 checkunknown(wc, p2) |
554 if not force: |
554 if not util.checkfolding(repo.path): |
555 checkunknown(wc, p2) |
555 checkcollision(p2) |
556 if not util.checkfolding(repo.path): |
556 if not branchmerge: |
557 checkcollision(p2) |
557 action += forgetremoved(wc, p2) |
558 if not branchmerge: |
558 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
559 action += forgetremoved(wc, p2) |
559 |
560 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
560 ### apply phase |
561 |
561 if not branchmerge: # just jump to the new rev |
562 ### apply phase |
562 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
563 if not branchmerge: # just jump to the new rev |
563 if not partial: |
564 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
564 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
565 if not partial: |
565 |
566 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
566 stats = applyupdates(repo, action, wc, p2) |
567 |
567 |
568 stats = applyupdates(repo, action, wc, p2) |
568 if not partial: |
569 |
569 recordupdates(repo, action, branchmerge) |
570 if not partial: |
570 repo.dirstate.setparents(fp1, fp2) |
571 recordupdates(repo, action, branchmerge) |
571 if not branchmerge and not fastforward: |
572 repo.dirstate.setparents(fp1, fp2) |
572 repo.dirstate.setbranch(p2.branch()) |
573 if not branchmerge and not fastforward: |
573 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3]) |
574 repo.dirstate.setbranch(p2.branch()) |
574 |
575 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3]) |
575 return stats |
576 |
576 finally: |
577 return stats |
577 del wlock |
578 |
|