# HG changeset patch # User Sune Foldager # Date 2009-05-23 15:04:31 # Node ID 6b9ec23b09fcf3436df14826137adb9ff5284dbe # Parent f8ff65a8316937d028402b96d0160072804709b5 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 diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1429,42 +1429,97 @@ class localrepository(repo.repository): 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] + + remotehds = remote.branchmap() - 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 + 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 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: + if inc: self.ui.warn(_("note: unsynced remote changes!\n")) diff --git a/tests/test-acl.out b/tests/test-acl.out --- a/tests/test-acl.out +++ b/tests/test-acl.out @@ -42,6 +42,7 @@ pretxnchangegroup.acl = python:hgext.acl 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 @@ sources = push 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 @@ sources = push 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 @@ foo/Bar/** = fred pushing to ../b searching for changes common changesets up to 6675d58eff77 +invalidating branch cache (tip differs) 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7