Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hg.py @ 254:c03f58e5fd2d
unify checkout and resolve into update
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
unify checkout and resolve into update
This replaces checkout and resolve with a single command:
$ hg help co
hg update [node]
update or merge working directory
If there are no outstanding changes in the working directory and
there is a linear relationship between the current version and the
requested version, the result is the requested version.
Otherwise the result is a merge between the contents of the
current working directory and the requested version. Files that
changed between either parent are marked as changed for the next
commit and a commit must be performed before any further updates
are allowed.
manifest hash: 513d285d7fb775d0560de49387042a685ea062f7
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFComS7ywK+sNU5EO8RAmgRAJ96GA6qvHLy0Jp0fzUrR2os2azPuACePsdC
YBldZtA7yIuTnV2vIbn7OSE=
=QtM/
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Sat, 04 Jun 2005 18:34:35 -0800 |
parents | 2da0a56aa1fd |
children | 649ed23e4661 |
comparison
equal
deleted
inserted
replaced
253:2da0a56aa1fd | 254:c03f58e5fd2d |
---|---|
325 | 325 |
326 def lookup(self, key): | 326 def lookup(self, key): |
327 if self.tags is None: | 327 if self.tags is None: |
328 self.tags = {} | 328 self.tags = {} |
329 try: | 329 try: |
330 # read each head of the tags file, ending with the tip | |
331 # and add each tag found to the map, with "newer" ones | |
332 # taking precedence | |
330 fl = self.file(".hgtags") | 333 fl = self.file(".hgtags") |
331 for l in fl.revision(fl.tip()).splitlines(): | 334 h = fl.heads() |
332 if l: | 335 h.reverse() |
333 n, k = l.split(" ") | 336 for r in h: |
334 self.tags[k] = bin(n) | 337 for l in fl.revision(r).splitlines(): |
338 if l: | |
339 n, k = l.split(" ") | |
340 self.tags[k] = bin(n) | |
335 except KeyError: pass | 341 except KeyError: pass |
336 try: | 342 try: |
337 return self.tags[key] | 343 return self.tags[key] |
338 except KeyError: | 344 except KeyError: |
339 return self.changelog.lookup(key) | 345 return self.changelog.lookup(key) |
473 tr.close() | 479 tr.close() |
474 | 480 |
475 self.dirstate.setparents(n) | 481 self.dirstate.setparents(n) |
476 self.dirstate.update(new, "n") | 482 self.dirstate.update(new, "n") |
477 self.dirstate.forget(remove) | 483 self.dirstate.forget(remove) |
478 | |
479 def checkout(self, node): | |
480 # checkout is really dumb at the moment | |
481 # it ought to basically merge | |
482 change = self.changelog.read(node) | |
483 l = self.manifest.read(change[0]).items() | |
484 l.sort() | |
485 | |
486 for f,n in l: | |
487 if f[0] == "/": continue | |
488 self.ui.note(f, "\n") | |
489 t = self.file(f).revision(n) | |
490 try: | |
491 file(self.wjoin(f), "w").write(t) | |
492 except IOError: | |
493 os.makedirs(os.path.dirname(f)) | |
494 file(self.wjoin(f), "w").write(t) | |
495 | |
496 self.dirstate.setparents(node) | |
497 self.dirstate.clear() | |
498 self.dirstate.update([f for f,n in l], "n") | |
499 | 484 |
500 def diffdir(self, path, changeset = None): | 485 def diffdir(self, path, changeset = None): |
501 changed = [] | 486 changed = [] |
502 added = [] | 487 added = [] |
503 unknown = [] | 488 unknown = [] |
846 % (files, changesets, revisions)) | 831 % (files, changesets, revisions)) |
847 | 832 |
848 tr.close() | 833 tr.close() |
849 return | 834 return |
850 | 835 |
851 def resolve(self, node): | 836 def update(self, node): |
852 pl = self.dirstate.parents() | 837 pl = self.dirstate.parents() |
853 if pl[1] != nullid: | 838 if pl[1] != nullid: |
854 self.ui.warn("last merge not committed") | 839 self.ui.warn("aborting: outstanding uncommitted merges\n") |
855 return | 840 return |
856 | 841 |
857 p1, p2 = pl[0], node | 842 p1, p2 = pl[0], node |
858 m1n = self.changelog.read(p1)[0] | 843 m1n = self.changelog.read(p1)[0] |
859 m2n = self.changelog.read(p2)[0] | 844 m2n = self.changelog.read(p2)[0] |
864 | 849 |
865 (c, a, d, u) = self.diffdir(self.root) | 850 (c, a, d, u) = self.diffdir(self.root) |
866 | 851 |
867 # resolve the manifest to determine which files | 852 # resolve the manifest to determine which files |
868 # we care about merging | 853 # we care about merging |
869 self.ui.status("resolving manifests\n") | 854 self.ui.note("resolving manifests\n") |
870 self.ui.debug(" ancestor %s local %s remote %s\n" % | 855 self.ui.debug(" ancestor %s local %s remote %s\n" % |
871 (short(man), short(m1n), short(m2n))) | 856 (short(man), short(m1n), short(m2n))) |
872 | 857 |
873 merge = {} | 858 merge = {} |
874 get = {} | 859 get = {} |
875 remove = [] | 860 remove = [] |
876 | 861 |
877 # construct a working dir manifest | 862 # construct a working dir manifest |
878 mw = m1.copy() | 863 mw = m1.copy() |
879 for f in a + c: | 864 for f in a + c + u: |
880 mw[f] = nullid | 865 mw[f] = "" |
881 for f in d: | 866 for f in d: |
882 del mw[f] | 867 if f in mw: del mw[f] |
883 | 868 |
884 for f, n in mw.iteritems(): | 869 for f, n in mw.iteritems(): |
885 if f in m2: | 870 if f in m2: |
886 if n != m2[f]: | 871 if n != m2[f]: |
887 self.ui.debug(" %s versions differ, do resolve\n" % f) | 872 a = ma.get(f, nullid) |
888 merge[f] = (m1.get(f, nullid), m2[f]) | 873 if n != a and m2[f] != a: |
874 self.ui.debug(" %s versions differ, do resolve\n" % f) | |
875 merge[f] = (m1.get(f, nullid), m2[f]) | |
876 else: | |
877 get[f] = m2[f] | |
889 del m2[f] | 878 del m2[f] |
890 elif f in ma: | 879 elif f in ma: |
891 if n != ma[f]: | 880 if n != ma[f]: |
892 r = self.ui.prompt( | 881 r = self.ui.prompt( |
893 (" local changed %s which remote deleted\n" % f) + | 882 (" local changed %s which remote deleted\n" % f) + |
894 "(k)eep or (d)elete?", "[kd]", "k") | 883 "(k)eep or (d)elete?", "[kd]", "k") |
895 if r == "d": | 884 if r == "d": |
896 remove.append(f) | 885 remove.append(f) |
897 else: | 886 else: |
898 self.ui.debug("other deleted %s\n" % f) | 887 self.ui.debug("other deleted %s\n" % f) |
899 pass # other deleted it | 888 remove.append(f) # other deleted it |
900 else: | 889 else: |
901 self.ui.debug("local created %s\n" %f) | 890 if n == m1.get(f, nullid): # same as parent |
891 self.ui.debug("remote deleted %s\n" % f) | |
892 remove.append(f) | |
893 else: | |
894 self.ui.debug("working dir created %s, keeping\n" % f) | |
902 | 895 |
903 for f, n in m2.iteritems(): | 896 for f, n in m2.iteritems(): |
904 if f in ma: | 897 if f in ma and n != ma[f]: |
905 if n != ma[f]: | |
906 r = self.ui.prompt( | 898 r = self.ui.prompt( |
907 ("remote changed %s which local deleted\n" % f) + | 899 ("remote changed %s which local deleted\n" % f) + |
908 "(k)eep or (d)elete?", "[kd]", "k") | 900 "(k)eep or (d)elete?", "[kd]", "k") |
909 if r == "d": remove.append(f) | 901 if r == "d": remove.append(f) |
910 else: | |
911 pass # probably safe | |
912 else: | 902 else: |
913 self.ui.debug("remote created %s, do resolve\n" % f) | 903 self.ui.debug("remote created %s\n" % f) |
914 get[f] = n | 904 get[f] = n |
915 | 905 |
916 del mw, m1, m2, ma | 906 del mw, m1, m2, ma |
907 | |
908 if not merge: | |
909 # we don't need to do any magic, just jump to the new rev | |
910 mode = 'n' | |
911 p1, p2 = p2, nullid | |
912 else: | |
913 # we have to remember what files we needed to get/change | |
914 # because any file that's different from either one of its | |
915 # parents must be in the changeset | |
916 mode = 'm' | |
917 | 917 |
918 self.dirstate.setparents(p1, p2) | 918 self.dirstate.setparents(p1, p2) |
919 | 919 |
920 # get the files we don't need to change | 920 # get the files we don't need to change |
921 files = get.keys() | 921 files = get.keys() |
927 try: | 927 try: |
928 file(self.wjoin(f), "w").write(t) | 928 file(self.wjoin(f), "w").write(t) |
929 except IOError: | 929 except IOError: |
930 os.makedirs(os.path.dirname(f)) | 930 os.makedirs(os.path.dirname(f)) |
931 file(self.wjoin(f), "w").write(t) | 931 file(self.wjoin(f), "w").write(t) |
932 | 932 self.dirstate.update([f], mode) |
933 # we have to remember what files we needed to get/change | |
934 # because any file that's different from either one of its | |
935 # parents must be in the changeset | |
936 self.dirstate.update(files, 'm') | |
937 | 933 |
938 # merge the tricky bits | 934 # merge the tricky bits |
939 files = merge.keys() | 935 files = merge.keys() |
940 files.sort() | 936 files.sort() |
941 for f in files: | 937 for f in files: |
938 self.status("mering %f\n" % f) | |
942 m, o = merge[f] | 939 m, o = merge[f] |
943 self.merge3(f, m, o) | 940 self.merge3(f, m, o) |
944 | 941 self.dirstate.update([f], 'm') |
945 # same here | |
946 self.dirstate.update(files, 'm') | |
947 | 942 |
948 for f in remove: | 943 for f in remove: |
949 self.ui.note("removing %s\n" % f) | 944 self.ui.note("removing %s\n" % f) |
950 #os.unlink(f) | 945 os.unlink(f) |
951 self.dirstate.update(remove, 'r') | 946 if mode == 'n': |
947 self.dirstate.forget(remove) | |
948 else: | |
949 self.dirstate.update(remove, 'r') | |
952 | 950 |
953 def merge3(self, fn, my, other): | 951 def merge3(self, fn, my, other): |
954 """perform a 3-way merge in the working directory""" | 952 """perform a 3-way merge in the working directory""" |
955 | 953 |
956 import tempfile | 954 import tempfile |