[PATCH 3 of 5] named branches: improve pre-push logic (issue736)

Henrik Stuart henrik.stuart at edlund.dk
Sat May 23 10:11:13 CDT 2009


# HG changeset patch
# User Sune Foldager <cryo at cyanite.org>
# Date 1243091071 -7200
# Node ID 053a8340306b6efc71db586e40fb6c1776a6036c
# Parent  46cd19ff9c4a949733e48eca90d5b755d5d8c86b
named branches: improve pre-push logic (issue736)

Each named branch is considered separately, and the push is allowed if
no new branch heads are created for any named branch to be pushed.

Due to some tests's use of --debug, their output will change after this
addition. This has been fixed as well.

Co-contributor: Henrik Stuart <henrik.stuart at edlund.dk>

diff -r 46cd19ff9c4a -r 053a8340306b mercurial/localrepo.py
--- a/mercurial/localrepo.py	Sat May 23 17:03:51 2009 +0200
+++ b/mercurial/localrepo.py	Sat May 23 17:04:31 2009 +0200
@@ -1429,42 +1429,97 @@
         else:
             bases, heads = update, self.changelog.heads()
 
+        def checkbranch(lheads, rheads, updatelh):
+            '''
+            check whether there are more local heads than remote heads on
+            a specific branch.
+
+            lheads: local branch heads
+            rheads: remote branch heads
+            updatelh: outgoing local branch heads
+            '''
+
+            warn = 0
+
+            if not revs and len(lheads) > len(rheads):
+                warn = 1
+            else:
+                updatelheads = [self.changelog.heads(x, lheads)
+                                for x in updatelh]
+                newheads = set(sum(updatelheads, [])) & set(lheads)
+
+                if not newheads:
+                    return True
+
+                for r in rheads:
+                    if r in self.changelog.nodemap:
+                        desc = self.changelog.heads(r, heads)
+                        l = [h for h in heads if h in desc]
+                        if not l:
+                            newheads.add(r)
+                    else:
+                        newheads.add(r)
+                if len(newheads) > len(rheads):
+                    warn = 1
+
+            if warn:
+                if not rheads: # new branch requires --force
+                    self.ui.warn(_("abort: push creates new"
+                                   " remote branch '%s'!\n" %
+                                   self[updatelh[0]].branch()))
+                else:
+                    self.ui.warn(_("abort: push creates new remote heads!\n"))
+
+                self.ui.status(_("(did you forget to merge?"
+                                 " use push -f to force)\n"))
+                return False
+            return True
+
         if not bases:
             self.ui.status(_("no changes found\n"))
             return None, 1
         elif not force:
-            # check if we're creating new remote heads
-            # to be a remote head after push, node must be either
+            # Check for each named branch if we're creating new remote heads.
+            # To be a remote head after push, node must be either:
             # - unknown locally
             # - a local outgoing head descended from update
             # - a remote head that's known locally and not
             #   ancestral to an outgoing head
+            #
+            # New named branches cannot be created without --force.
 
-            warn = 0
+            if remote_heads != [nullid]:
+                if remote.capable('branchmap'):
+                    localhds = {}
+                    if not revs:
+                        localhds = self.branchmap()
+                    else:
+                        for n in heads:
+                            branch = self[n].branch()
+                            if branch in localhds:
+                                localhds[branch].append(n)
+                            else:
+                                localhds[branch] = [n]
 
-            if remote_heads == [nullid]:
-                warn = 0
-            elif not revs and len(heads) > len(remote_heads):
-                warn = 1
-            else:
-                newheads = list(heads)
-                for r in remote_heads:
-                    if r in self.changelog.nodemap:
-                        desc = self.changelog.heads(r, heads)
-                        l = [h for h in heads if h in desc]
-                        if not l:
-                            newheads.append(r)
-                    else:
-                        newheads.append(r)
-                if len(newheads) > len(remote_heads):
-                    warn = 1
+                    remotehds = remote.branchmap()
 
-            if warn:
-                self.ui.warn(_("abort: push creates new remote heads!\n"))
-                self.ui.status(_("(did you forget to merge?"
-                                 " use push -f to force)\n"))
-                return None, 0
-            elif inc:
+                    for lh in localhds:
+                        if lh in remotehds:
+                            rheads = remotehds[lh]
+                        else:
+                            rheads = []
+                        lheads = localhds[lh]
+                        updatelh = [upd for upd in update
+                                    if self[upd].branch() == lh]
+                        if not updatelh:
+                            continue
+                        if not checkbranch(lheads, rheads, updatelh):
+                            return None, 0
+                else:
+                    if not checkbranch(heads, remote_heads, update):
+                        return None, 0
+
+            if inc:
                 self.ui.warn(_("note: unsynced remote changes!\n"))
 
 
diff -r 46cd19ff9c4a -r 053a8340306b tests/test-acl.out
--- a/tests/test-acl.out	Sat May 23 17:03:51 2009 +0200
+++ b/tests/test-acl.out	Sat May 23 17:04:31 2009 +0200
@@ -42,6 +42,7 @@
 pushing to ../b
 searching for changes
 common changesets up to 6675d58eff77
+invalidating branch cache (tip differs)
 3 changesets found
 list of changesets:
 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
@@ -74,6 +75,7 @@
 pushing to ../b
 searching for changes
 common changesets up to 6675d58eff77
+invalidating branch cache (tip differs)
 3 changesets found
 list of changesets:
 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
@@ -111,6 +113,7 @@
 pushing to ../b
 searching for changes
 common changesets up to 6675d58eff77
+invalidating branch cache (tip differs)
 3 changesets found
 list of changesets:
 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
@@ -408,6 +411,7 @@
 pushing to ../b
 searching for changes
 common changesets up to 6675d58eff77
+invalidating branch cache (tip differs)
 3 changesets found
 list of changesets:
 ef1ea85a6374b77d6da9dcda9541f498f2d17df7


More information about the Mercurial-devel mailing list