Fix hg push and hg push -r sometimes creating new heads without --force.
authorThomas Arendsen Hein <thomas@intevation.de>
Wed, 29 Mar 2006 22:35:21 +0200
changeset 2021 fc22ed56afe3
parent 2020 00925397236c
child 2022 a59da8cc35e4
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.
mercurial/localrepo.py
tests/test-push-warn
tests/test-push-warn.out
--- a/mercurial/localrepo.py	Wed Mar 29 10:31:58 2006 -0800
+++ b/mercurial/localrepo.py	Wed Mar 29 22:35:21 2006 +0200
@@ -923,6 +923,14 @@
         return fetch.keys()
 
     def findoutgoing(self, remote, base=None, heads=None, force=False):
+        """Return list of nodes that are roots of subsets not in remote
+
+        If base dict is specified, assume that these nodes and their parents
+        exist on the remote side.
+        If a list of heads is specified, return only nodes which are heads
+        or ancestors of these heads, and return a second element which
+        contains all remote heads which get new children.
+        """
         if base == None:
             base = {}
             self.findincoming(remote, base, heads, force=force)
@@ -944,13 +952,23 @@
 
         # find every node whose parents have been pruned
         subset = []
+        # find every remote head that will get new children
+        updated_heads = {}
         for n in remain:
             p1, p2 = self.changelog.parents(n)
             if p1 not in remain and p2 not in remain:
                 subset.append(n)
+            if heads:
+                if p1 in heads:
+                    updated_heads[p1] = True
+                if p2 in heads:
+                    updated_heads[p2] = True
 
         # this is the set of all roots we have to push
-        return subset
+        if heads:
+            return subset, updated_heads.keys()
+        else:
+            return subset
 
     def pull(self, remote, heads=None, force=False):
         l = self.lock()
@@ -976,14 +994,15 @@
         lock = remote.lock()
 
         base = {}
-        heads = remote.heads()
-        inc = self.findincoming(remote, base, heads, force=force)
+        remote_heads = remote.heads()
+        inc = self.findincoming(remote, base, remote_heads, force=force)
         if not force and inc:
             self.ui.warn(_("abort: unsynced remote changes!\n"))
-            self.ui.status(_("(did you forget to sync? use push -f to force)\n"))
+            self.ui.status(_("(did you forget to sync?"
+                             " use push -f to force)\n"))
             return 1
 
-        update = self.findoutgoing(remote, base)
+        update, updated_heads = self.findoutgoing(remote, base, remote_heads)
         if revs is not None:
             msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
         else:
@@ -993,7 +1012,14 @@
             self.ui.status(_("no changes found\n"))
             return 1
         elif not force:
-            if len(bases) < len(heads):
+            if revs is not None:
+                updated_heads = {}
+                for base in msng_cl:
+                    for parent in self.changelog.parents(base):
+                        if parent in remote_heads:
+                            updated_heads[parent] = True
+                updated_heads = updated_heads.keys()
+            if len(updated_heads) < len(heads):
                 self.ui.warn(_("abort: push creates new remote branches!\n"))
                 self.ui.status(_("(did you forget to merge?"
                                  " use push -f to force)\n"))
--- a/tests/test-push-warn	Wed Mar 29 10:31:58 2006 -0800
+++ b/tests/test-push-warn	Wed Mar 29 22:35:21 2006 +0200
@@ -26,3 +26,30 @@
 hg up -m
 hg commit -m "4" -d "1000000 0"
 hg push ../a
+cd ..
+
+hg init c
+cd c
+for i in 0 1 2; do
+    echo $i >> foo
+    hg ci -Am $i -d "1000000 0"
+done
+cd ..
+
+hg clone c d
+cd d
+for i in 0 1; do
+    hg co -C $i
+    echo d-$i >> foo
+    hg ci -m d-$i -d "1000000 0"
+done
+
+HGMERGE=true hg co -m 3
+hg ci -m c-d -d "1000000 0"
+
+hg push ../c
+hg push -r 2 ../c
+hg push -r 3 -r 4 ../c
+hg push -r 5 ../c
+
+exit 0
--- a/tests/test-push-warn.out	Wed Mar 29 10:31:58 2006 -0800
+++ b/tests/test-push-warn.out	Wed Mar 29 22:35:21 2006 +0200
@@ -19,3 +19,20 @@
 adding manifests
 adding file changes
 added 2 changesets with 1 changes to 1 files
+adding foo
+merging foo
+pushing to ../c
+searching for changes
+abort: push creates new remote branches!
+(did you forget to merge? use push -f to force)
+pushing to ../c
+searching for changes
+no changes found
+pushing to ../c
+searching for changes
+abort: push creates new remote branches!
+(did you forget to merge? use push -f to force)
+pushing to ../c
+searching for changes
+abort: push creates new remote branches!
+(did you forget to merge? use push -f to force)