Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/hg.py @ 990:5007e0bdeed2
Fix long-standing excessive file merges
Since switching to the multihead approach, we've been creating
excessive file-level merges where files are marked as merged with
their ancestors.
This explicitly checks at commit time whether the two parent versions
are linearly related, and if so, reduces the file check-in to a
non-merge. Then the file is compared against the remaining parent,
and, if equal, skips check-in of that file (as it's not changed).
Since we're not checking in all files that were different between
versions, we no longer need to mark so many files for merge. This
removes most of the 'm' state marking as well.
Finally, it is possible to do a tree-level merge with no file-level
changes. This will happen if one user changes file A and another
changes file B. Thus, if we have have two parents, we allow commit to
proceed even if there are no file-level changes.
author | mpm@selenic.com |
---|---|
date | Sun, 21 Aug 2005 21:59:55 -0700 |
parents | 4f81068ed8cd |
children | b634b15c020b |
comparison
equal
deleted
inserted
replaced
989:1b6eb272b238 | 990:5007e0bdeed2 |
---|---|
838 try: | 838 try: |
839 t = self.wfile(f).read() | 839 t = self.wfile(f).read() |
840 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) | 840 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) |
841 r = self.file(f) | 841 r = self.file(f) |
842 mfm[f] = tm | 842 mfm[f] = tm |
843 mm[f] = r.add(t, {}, tr, linkrev, | 843 |
844 m1.get(f, nullid), m2.get(f, nullid)) | 844 fp1 = m1.get(f, nullid) |
845 fp2 = m2.get(f, nullid) | |
846 | |
847 # is the same revision on two branches of a merge? | |
848 if fp2 == fp1: | |
849 fp2 = nullid | |
850 | |
851 if fp2 != nullid: | |
852 # is one parent an ancestor of the other? | |
853 fpa = r.ancestor(fp1, fp2) | |
854 if fpa == fp1: | |
855 fp1, fp2 = fp2, nullid | |
856 elif fpa == fp2: | |
857 fp2 = nullid | |
858 | |
859 # is the file unmodified from the parent? | |
860 if t == r.read(fp1): | |
861 # record the proper existing parent in manifest | |
862 # no need to add a revision | |
863 mm[f] = fp1 | |
864 continue | |
865 | |
866 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) | |
845 if update_dirstate: | 867 if update_dirstate: |
846 self.dirstate.update([f], "n") | 868 self.dirstate.update([f], "n") |
847 except IOError: | 869 except IOError: |
848 try: | 870 try: |
849 del mm[f] | 871 del mm[f] |
877 else: | 899 else: |
878 (c, a, d, u) = self.changes(match = match) | 900 (c, a, d, u) = self.changes(match = match) |
879 commit = c + a | 901 commit = c + a |
880 remove = d | 902 remove = d |
881 | 903 |
882 if not commit and not remove and not force: | |
883 self.ui.status("nothing changed\n") | |
884 return None | |
885 | |
886 if not self.hook("precommit"): | |
887 return None | |
888 | |
889 p1, p2 = self.dirstate.parents() | 904 p1, p2 = self.dirstate.parents() |
890 c1 = self.changelog.read(p1) | 905 c1 = self.changelog.read(p1) |
891 c2 = self.changelog.read(p2) | 906 c2 = self.changelog.read(p2) |
892 m1 = self.manifest.read(c1[0]) | 907 m1 = self.manifest.read(c1[0]) |
893 mf1 = self.manifest.readflags(c1[0]) | 908 mf1 = self.manifest.readflags(c1[0]) |
894 m2 = self.manifest.read(c2[0]) | 909 m2 = self.manifest.read(c2[0]) |
910 | |
911 if not commit and not remove and not force and p2 == nullid: | |
912 self.ui.status("nothing changed\n") | |
913 return None | |
914 | |
915 if not self.hook("precommit"): | |
916 return None | |
917 | |
895 lock = self.lock() | 918 lock = self.lock() |
896 tr = self.transaction() | 919 tr = self.transaction() |
897 | 920 |
898 # check in files | 921 # check in files |
899 new = {} | 922 new = {} |
916 self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"])) | 939 self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"])) |
917 | 940 |
918 r = self.file(f) | 941 r = self.file(f) |
919 fp1 = m1.get(f, nullid) | 942 fp1 = m1.get(f, nullid) |
920 fp2 = m2.get(f, nullid) | 943 fp2 = m2.get(f, nullid) |
944 | |
945 # is the same revision on two branches of a merge? | |
946 if fp2 == fp1: | |
947 fp2 = nullid | |
948 | |
949 if fp2 != nullid: | |
950 # is one parent an ancestor of the other? | |
951 fpa = r.ancestor(fp1, fp2) | |
952 if fpa == fp1: | |
953 fp1, fp2 = fp2, nullid | |
954 elif fpa == fp2: | |
955 fp2 = nullid | |
956 | |
957 # is the file unmodified from the parent? | |
958 if not meta and t == r.read(fp1): | |
959 # record the proper existing parent in manifest | |
960 # no need to add a revision | |
961 new[f] = fp1 | |
962 continue | |
963 | |
921 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) | 964 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) |
922 | 965 |
923 # update manifest | 966 # update manifest |
924 m1.update(new) | 967 m1.update(new) |
925 for f in remove: | 968 for f in remove: |
1713 self.ui.status(" %s%s\n" % (f, cf)) | 1756 self.ui.status(" %s%s\n" % (f, cf)) |
1714 self.ui.warn("aborting update spanning branches!\n") | 1757 self.ui.warn("aborting update spanning branches!\n") |
1715 self.ui.status("(use update -m to merge across branches" + | 1758 self.ui.status("(use update -m to merge across branches" + |
1716 " or -C to lose changes)\n") | 1759 " or -C to lose changes)\n") |
1717 return 1 | 1760 return 1 |
1718 # we have to remember what files we needed to get/change | |
1719 # because any file that's different from either one of its | |
1720 # parents must be in the changeset | |
1721 mode = 'm' | 1761 mode = 'm' |
1722 if moddirstate: | |
1723 self.dirstate.update(mark.keys(), "m") | |
1724 | 1762 |
1725 if moddirstate: | 1763 if moddirstate: |
1726 self.dirstate.setparents(p1, p2) | 1764 self.dirstate.setparents(p1, p2) |
1727 | 1765 |
1728 # get the files we don't need to change | 1766 # get the files we don't need to change |
1737 except IOError: | 1775 except IOError: |
1738 os.makedirs(os.path.dirname(self.wjoin(f))) | 1776 os.makedirs(os.path.dirname(self.wjoin(f))) |
1739 self.wfile(f, "w").write(t) | 1777 self.wfile(f, "w").write(t) |
1740 util.set_exec(self.wjoin(f), mf2[f]) | 1778 util.set_exec(self.wjoin(f), mf2[f]) |
1741 if moddirstate: | 1779 if moddirstate: |
1742 self.dirstate.update([f], mode) | 1780 self.dirstate.update([f], 'n') |
1743 | 1781 |
1744 # merge the tricky bits | 1782 # merge the tricky bits |
1745 files = merge.keys() | 1783 files = merge.keys() |
1746 files.sort() | 1784 files.sort() |
1747 for f in files: | 1785 for f in files: |