Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/hg.py @ 146:4a828422247d
Handle merge with deletions
If you merge with a repo that has deleted a file after editing it, hg
attempted to resolve the file. This (correctly) resulted in hg verify
errors because the resolved version didn't show up in the manifests.
This moves the manifest resolution before file resolution and decides
which files to resolve based on the (partially) resolved manifest.
After files are resolved, the final manifest is committed.
author | mpm@selenic.com |
---|---|
date | Tue, 24 May 2005 20:30:35 -0800 |
parents | ea9188538222 |
children | c32286d0a665 |
comparison
equal
deleted
inserted
replaced
145:fbce9fc531d2 | 146:4a828422247d |
---|---|
610 l = struct.unpack(">l", d)[0] | 610 l = struct.unpack(">l", d)[0] |
611 return source.read(l - 4 + add) | 611 return source.read(l - 4 + add) |
612 | 612 |
613 tr = self.transaction() | 613 tr = self.transaction() |
614 simple = True | 614 simple = True |
615 need = {} | |
615 | 616 |
616 self.ui.status("adding changesets\n") | 617 self.ui.status("adding changesets\n") |
617 # pull off the changeset group | 618 # pull off the changeset group |
618 def report(x): | 619 def report(x): |
619 self.ui.debug("add changeset %s\n" % short(x)) | 620 self.ui.debug("add changeset %s\n" % short(x)) |
632 # do we need a resolve? | 633 # do we need a resolve? |
633 if self.changelog.ancestor(co, cn) != co: | 634 if self.changelog.ancestor(co, cn) != co: |
634 simple = False | 635 simple = False |
635 resolverev = self.changelog.count() | 636 resolverev = self.changelog.count() |
636 | 637 |
638 # resolve the manifest to determine which files | |
639 # we care about merging | |
640 self.ui.status("resolving manifests\n") | |
641 ma = self.manifest.ancestor(mm, mo) | |
642 omap = self.manifest.read(mo) # other | |
643 amap = self.manifest.read(ma) # ancestor | |
644 mmap = self.manifest.read(mm) # mine | |
645 nmap = {} | |
646 | |
647 self.ui.debug(" ancestor %s local %s remote %s\n" % | |
648 (short(ma), short(mm), short(mo))) | |
649 | |
650 for f, mid in mmap.iteritems(): | |
651 if f in omap: | |
652 if mid != omap[f]: | |
653 self.ui.debug(" %s versions differ, do resolve\n" % f) | |
654 need[f] = mid # use merged version or local version | |
655 else: | |
656 nmap[f] = mid # keep ours | |
657 del omap[f] | |
658 elif f in amap: | |
659 if mid != amap[f]: | |
660 r = self.ui.prompt( | |
661 (" local changed %s which remote deleted\n" % f) + | |
662 "(k)eep or (d)elete?", "[kd]", "k") | |
663 if r == "k": nmap[f] = mid | |
664 else: | |
665 self.ui.debug("other deleted %s\n" % f) | |
666 pass # other deleted it | |
667 else: | |
668 self.ui.debug("local created %s\n" %f) | |
669 nmap[f] = mid # we created it | |
670 | |
671 del mmap | |
672 | |
673 for f, oid in omap.iteritems(): | |
674 if f in amap: | |
675 if oid != amap[f]: | |
676 r = self.ui.prompt( | |
677 ("remote changed %s which local deleted\n" % f) + | |
678 "(k)eep or (d)elete?", "[kd]", "k") | |
679 if r == "k": nmap[f] = oid | |
680 else: | |
681 pass # probably safe | |
682 else: | |
683 self.ui.debug("remote created %s, do resolve\n" % f) | |
684 need[f] = oid | |
685 | |
686 del omap | |
687 del amap | |
688 | |
689 new = need.keys() | |
690 new.sort() | |
691 | |
637 # process the files | 692 # process the files |
638 self.ui.status("adding files\n") | 693 self.ui.status("adding files\n") |
639 new = {} | |
640 while 1: | 694 while 1: |
641 f = getchunk(4) | 695 f = getchunk(4) |
642 if not f: break | 696 if not f: break |
643 fg = getchunk() | 697 fg = getchunk() |
644 self.ui.debug("adding %s revisions\n" % f) | 698 self.ui.debug("adding %s revisions\n" % f) |
645 fl = self.file(f) | 699 fl = self.file(f) |
646 o = fl.tip() | 700 o = fl.tip() |
647 n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr) | 701 n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr) |
648 if not simple: | 702 if f in need: |
649 if o == n: continue | 703 del need[f] |
650 # this file has changed between branches, so it must be | 704 # manifest resolve determined we need to merge the tips |
651 # represented in the merge changeset | 705 nmap[f] = self.merge3(fl, f, o, n, tr, resolverev) |
652 new[f] = self.merge3(fl, f, o, n, tr, resolverev) | 706 |
707 if need: | |
708 # we need to do trivial merges on local files | |
709 for f in new: | |
710 if f not in need: continue | |
711 fl = self.file(f) | |
712 nmap[f] = self.merge3(fl, f, need[f], fl.tip(), tr, resolverev) | |
653 | 713 |
654 # For simple merges, we don't need to resolve manifests or changesets | 714 # For simple merges, we don't need to resolve manifests or changesets |
655 if simple: | 715 if simple: |
656 self.ui.debug("simple merge, skipping resolve\n") | 716 self.ui.debug("simple merge, skipping resolve\n") |
657 tr.close() | 717 tr.close() |
658 return | 718 return |
659 | 719 |
660 # resolve the manifest to point to all the merged files | |
661 self.ui.status("resolving manifests\n") | |
662 ma = self.manifest.ancestor(mm, mo) | |
663 omap = self.manifest.read(mo) # other | |
664 amap = self.manifest.read(ma) # ancestor | |
665 mmap = self.manifest.read(mm) # mine | |
666 self.ui.debug("ancestor %s local %s remote %s\n" % | |
667 (short(ma), short(mm), short(mo))) | |
668 nmap = {} | |
669 | |
670 for f, mid in mmap.iteritems(): | |
671 if f in omap: | |
672 if mid != omap[f]: | |
673 self.ui.debug("%s versions differ\n" % f) | |
674 if f in new: self.ui.debug("%s updated in resolve\n" % f) | |
675 # use merged version or local version | |
676 nmap[f] = new.get(f, mid) | |
677 else: | |
678 nmap[f] = mid # keep ours | |
679 del omap[f] | |
680 elif f in amap: | |
681 if mid != amap[f]: | |
682 r = self.ui.prompt( | |
683 ("local changed %s which remote deleted\n" % f) + | |
684 "(k)eep or (d)elete?", "[kd]", "k") | |
685 if r == "k": nmap[f] = mid | |
686 else: | |
687 self.ui.debug("other deleted %s\n" % f) | |
688 pass # other deleted it | |
689 else: | |
690 self.ui.debug("local created %s\n" %f) | |
691 nmap[f] = mid # we created it | |
692 | |
693 del mmap | |
694 | |
695 for f, oid in omap.iteritems(): | |
696 if f in amap: | |
697 if oid != amap[f]: | |
698 r = self.ui.prompt( | |
699 ("remote changed %s which local deleted\n" % f) + | |
700 "(k)eep or (d)elete?", "[kd]", "k") | |
701 if r == "k": nmap[f] = oid | |
702 else: | |
703 pass # probably safe | |
704 else: | |
705 self.ui.debug("remote created %s\n" % f) | |
706 nmap[f] = new.get(f, oid) # remote created it | |
707 | |
708 del omap | |
709 del amap | |
710 | |
711 node = self.manifest.add(nmap, tr, resolverev, mm, mo) | 720 node = self.manifest.add(nmap, tr, resolverev, mm, mo) |
712 | 721 |
713 # Now all files and manifests are merged, we add the changed files | 722 # Now all files and manifests are merged, we add the changed files |
714 # and manifest id to the changelog | 723 # and manifest id to the changelog |
715 self.ui.status("committing merge changeset\n") | 724 self.ui.status("committing merge changeset\n") |
716 new = new.keys() | |
717 new.sort() | |
718 if co == cn: cn = -1 | 725 if co == cn: cn = -1 |
719 | 726 |
720 edittext = "\nHG: merge resolve\n" + \ | 727 edittext = "\nHG: merge resolve\n" + \ |
721 "".join(["HG: changed %s\n" % f for f in new]) | 728 "".join(["HG: changed %s\n" % f for f in new]) |
722 edittext = self.ui.edit(edittext) | 729 edittext = self.ui.edit(edittext) |