comparison mercurial/localrepo.py @ 2021:fc22ed56afe3

Fix hg push and hg push -r sometimes creating new heads without --force. Fixing issue179. The algorithm checks if there not more new heads on the remote side than heads which become non-heads due to getting children. Pushing this repo: m /\ 3 3a| |/ / 2 2a |/ 1 to a repo only having 1, 2 and 3 didn't abort requiring --force before. Added test cases for this and some doc strings for used methods.
author Thomas Arendsen Hein <thomas@intevation.de>
date Wed, 29 Mar 2006 22:35:21 +0200
parents 00925397236c
children a59da8cc35e4
comparison
equal deleted inserted replaced
2020:00925397236c 2021:fc22ed56afe3
921 self.ui.debug(_("%d total queries\n") % reqcnt) 921 self.ui.debug(_("%d total queries\n") % reqcnt)
922 922
923 return fetch.keys() 923 return fetch.keys()
924 924
925 def findoutgoing(self, remote, base=None, heads=None, force=False): 925 def findoutgoing(self, remote, base=None, heads=None, force=False):
926 """Return list of nodes that are roots of subsets not in remote
927
928 If base dict is specified, assume that these nodes and their parents
929 exist on the remote side.
930 If a list of heads is specified, return only nodes which are heads
931 or ancestors of these heads, and return a second element which
932 contains all remote heads which get new children.
933 """
926 if base == None: 934 if base == None:
927 base = {} 935 base = {}
928 self.findincoming(remote, base, heads, force=force) 936 self.findincoming(remote, base, heads, force=force)
929 937
930 self.ui.debug(_("common changesets up to ") 938 self.ui.debug(_("common changesets up to ")
942 for p in self.changelog.parents(n): 950 for p in self.changelog.parents(n):
943 remove.append(p) 951 remove.append(p)
944 952
945 # find every node whose parents have been pruned 953 # find every node whose parents have been pruned
946 subset = [] 954 subset = []
955 # find every remote head that will get new children
956 updated_heads = {}
947 for n in remain: 957 for n in remain:
948 p1, p2 = self.changelog.parents(n) 958 p1, p2 = self.changelog.parents(n)
949 if p1 not in remain and p2 not in remain: 959 if p1 not in remain and p2 not in remain:
950 subset.append(n) 960 subset.append(n)
961 if heads:
962 if p1 in heads:
963 updated_heads[p1] = True
964 if p2 in heads:
965 updated_heads[p2] = True
951 966
952 # this is the set of all roots we have to push 967 # this is the set of all roots we have to push
953 return subset 968 if heads:
969 return subset, updated_heads.keys()
970 else:
971 return subset
954 972
955 def pull(self, remote, heads=None, force=False): 973 def pull(self, remote, heads=None, force=False):
956 l = self.lock() 974 l = self.lock()
957 975
958 # if we have an empty repo, fetch everything 976 # if we have an empty repo, fetch everything
974 992
975 def push(self, remote, force=False, revs=None): 993 def push(self, remote, force=False, revs=None):
976 lock = remote.lock() 994 lock = remote.lock()
977 995
978 base = {} 996 base = {}
979 heads = remote.heads() 997 remote_heads = remote.heads()
980 inc = self.findincoming(remote, base, heads, force=force) 998 inc = self.findincoming(remote, base, remote_heads, force=force)
981 if not force and inc: 999 if not force and inc:
982 self.ui.warn(_("abort: unsynced remote changes!\n")) 1000 self.ui.warn(_("abort: unsynced remote changes!\n"))
983 self.ui.status(_("(did you forget to sync? use push -f to force)\n")) 1001 self.ui.status(_("(did you forget to sync?"
1002 " use push -f to force)\n"))
984 return 1 1003 return 1
985 1004
986 update = self.findoutgoing(remote, base) 1005 update, updated_heads = self.findoutgoing(remote, base, remote_heads)
987 if revs is not None: 1006 if revs is not None:
988 msng_cl, bases, heads = self.changelog.nodesbetween(update, revs) 1007 msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
989 else: 1008 else:
990 bases, heads = update, self.changelog.heads() 1009 bases, heads = update, self.changelog.heads()
991 1010
992 if not bases: 1011 if not bases:
993 self.ui.status(_("no changes found\n")) 1012 self.ui.status(_("no changes found\n"))
994 return 1 1013 return 1
995 elif not force: 1014 elif not force:
996 if len(bases) < len(heads): 1015 if revs is not None:
1016 updated_heads = {}
1017 for base in msng_cl:
1018 for parent in self.changelog.parents(base):
1019 if parent in remote_heads:
1020 updated_heads[parent] = True
1021 updated_heads = updated_heads.keys()
1022 if len(updated_heads) < len(heads):
997 self.ui.warn(_("abort: push creates new remote branches!\n")) 1023 self.ui.warn(_("abort: push creates new remote branches!\n"))
998 self.ui.status(_("(did you forget to merge?" 1024 self.ui.status(_("(did you forget to merge?"
999 " use push -f to force)\n")) 1025 " use push -f to force)\n"))
1000 return 1 1026 return 1
1001 1027