# HG changeset patch # User Sune Foldager # Date 1274448149 -7200 # Node ID e43c23d189a586a06c533e7fdd5cef6a85e8a4e1 # Parent 0c0088881562670e47a11adf6fc468dfa7a17e9c push: add --new-branch option to allow intial push of new branches Compare this to --force which allows anything to be pushed. With --new-branch, only changesets to named branches not present on the and changesets not introducing additional heads on existing branches are allowed. Developed by Henrik Stuart Sune Foldager diff -r 0c0088881562 -r e43c23d189a5 hgext/mq.py --- a/hgext/mq.py Fri May 21 22:53:57 2010 +0900 +++ b/hgext/mq.py Fri May 21 15:22:29 2010 +0200 @@ -2555,10 +2555,10 @@ return super(mqrepo, self).commit(text, user, date, match, force, editor, extra) - def push(self, remote, force=False, revs=None): + def push(self, remote, force=False, revs=None, newbranch=False): if self.mq.applied and not force and not revs: raise util.Abort(_('source has mq patches applied')) - return super(mqrepo, self).push(remote, force, revs) + return super(mqrepo, self).push(remote, force, revs, newbranch) def _findtags(self): '''augment tags from base class with patch tags''' diff -r 0c0088881562 -r e43c23d189a5 mercurial/commands.py --- a/mercurial/commands.py Fri May 21 22:53:57 2010 +0900 +++ b/mercurial/commands.py Fri May 21 15:22:29 2010 +0200 @@ -2564,7 +2564,8 @@ if not c.sub(s).push(opts.get('force')): return False - r = repo.push(other, opts.get('force'), revs=revs) + r = repo.push(other, opts.get('force'), revs=revs, + newbranch=opts.get('new_branch')) return r == 0 def recover(ui, repo): @@ -3948,6 +3949,7 @@ _('a changeset intended to be included in the destination')), ('b', 'branch', [], _('a specific branch you would like to push')), + ('', 'new-branch', False, _('allow pushing a new branch')), ] + remoteopts, _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')), "recover": (recover, []), diff -r 0c0088881562 -r e43c23d189a5 mercurial/localrepo.py --- a/mercurial/localrepo.py Fri May 21 22:53:57 2010 +0900 +++ b/mercurial/localrepo.py Fri May 21 15:22:29 2010 +0200 @@ -1507,7 +1507,7 @@ finally: lock.release() - def push(self, remote, force=False, revs=None): + def push(self, remote, force=False, revs=None, newbranch=False): '''Push outgoing changesets (limited by revs) from the current repository to remote. Return an integer: - 0 means HTTP error *or* nothing to push @@ -1524,10 +1524,10 @@ # servers, http servers). if remote.capable('unbundle'): - return self.push_unbundle(remote, force, revs) - return self.push_addchangegroup(remote, force, revs) + return self.push_unbundle(remote, force, revs, newbranch) + return self.push_addchangegroup(remote, force, revs, newbranch) - def prepush(self, remote, force, revs): + def prepush(self, remote, force, revs, newbranch): '''Analyze the local and remote repositories and determine which changesets need to be pushed to the remote. Return value depends on circumstances: @@ -1586,13 +1586,15 @@ # 2. Check for new branches on the remote. remotemap = remote.branchmap() newbranches = branches - set(remotemap) - if newbranches: # new branch requires --force + if newbranches and not newbranch: # new branch requires --new-branch branchnames = ', '.join("%s" % b for b in newbranches) self.ui.warn(_("abort: push creates " "new remote branches: %s!\n") % branchnames) - self.ui.status(_("(use 'hg push -f' to force)\n")) + self.ui.status(_("(use 'hg push --new-branch' to create new " + "remote branches)\n")) return None, 0 + branches.difference_update(newbranches) # 3. Construct the initial oldmap and newmap dicts. # They contain information about the remote heads before and @@ -1654,14 +1656,14 @@ cg = self.changegroupsubset(update, revs, 'push') return cg, remote_heads - def push_addchangegroup(self, remote, force, revs): + def push_addchangegroup(self, remote, force, revs, newbranch): '''Push a changegroup by locking the remote and sending the addchangegroup command to it. Used for local and old SSH repos. Return an integer: see push(). ''' lock = remote.lock() try: - ret = self.prepush(remote, force, revs) + ret = self.prepush(remote, force, revs, newbranch) if ret[0] is not None: cg, remote_heads = ret # here, we return an integer indicating remote head count change @@ -1672,7 +1674,7 @@ finally: lock.release() - def push_unbundle(self, remote, force, revs): + def push_unbundle(self, remote, force, revs, newbranch): '''Push a changegroup by unbundling it on the remote. Used for new SSH and HTTP repos. Return an integer: see push().''' # local repo finds heads on server, finds out what revs it @@ -1680,7 +1682,7 @@ # different heads (someone else won commit/push race), server # aborts. - ret = self.prepush(remote, force, revs) + ret = self.prepush(remote, force, revs, newbranch) if ret[0] is not None: cg, remote_heads = ret if force: diff -r 0c0088881562 -r e43c23d189a5 tests/test-debugcomplete.out --- a/tests/test-debugcomplete.out Fri May 21 22:53:57 2010 +0900 +++ b/tests/test-debugcomplete.out Fri May 21 15:22:29 2010 +0200 @@ -174,7 +174,7 @@ log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude merge: force, rev, preview pull: update, force, rev, branch, ssh, remotecmd -push: force, rev, branch, ssh, remotecmd +push: force, rev, branch, new-branch, ssh, remotecmd remove: after, force, include, exclude serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude diff -r 0c0088881562 -r e43c23d189a5 tests/test-push-warn --- a/tests/test-push-warn Fri May 21 22:53:57 2010 +0900 +++ b/tests/test-push-warn Fri May 21 15:22:29 2010 +0200 @@ -135,6 +135,18 @@ hg -q ci -d "1000000 0" -m 12 hg push -r 11 -r 12 ../f; echo $? +echo % failed push of new named branch +echo 12 > foo +hg -q ci -d "1000000 0" -m 12a +hg -q up 11 +echo 13 > foo +hg -q branch e +hg -q ci -d "1000000 0" -m 13d +hg push -r 12 -r 13 ../f; echo $? + +echo % using --new-branch to push new named branch +hg push --new-branch -r 12 -r 13 ../f; echo $? + echo % checking prepush logic does not allow silently pushing multiple new heads cd .. hg init h diff -r 0c0088881562 -r e43c23d189a5 tests/test-push-warn.out --- a/tests/test-push-warn.out Fri May 21 22:53:57 2010 +0900 +++ b/tests/test-push-warn.out Fri May 21 15:22:29 2010 +0200 @@ -89,23 +89,23 @@ pushing to ../f searching for changes abort: push creates new remote branches: c! -(use 'hg push -f' to force) +(use 'hg push --new-branch' to create new remote branches) 1 pushing to ../f searching for changes abort: push creates new remote branches: c! -(use 'hg push -f' to force) +(use 'hg push --new-branch' to create new remote branches) 1 % multiple new branches pushing to ../f searching for changes abort: push creates new remote branches: c, d! -(use 'hg push -f' to force) +(use 'hg push --new-branch' to create new remote branches) 1 pushing to ../f searching for changes abort: push creates new remote branches: c, d! -(use 'hg push -f' to force) +(use 'hg push --new-branch' to create new remote branches) 1 % fail on multiple head push pushing to ../f @@ -144,6 +144,20 @@ adding file changes added 2 changesets with 2 changes to 1 files 0 +% failed push of new named branch +pushing to ../f +searching for changes +abort: push creates new remote branches: e! +(use 'hg push --new-branch' to create new remote branches) +1 +% using --new-branch to push new named branch +pushing to ../f +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +0 % checking prepush logic does not allow silently pushing multiple new heads adding init adding a @@ -172,7 +186,7 @@ pushing to j searching for changes abort: push creates new remote branches: b! -(use 'hg push -f' to force) +(use 'hg push --new-branch' to create new remote branches) % prepush -r should not allow you to sneak in new heads pushing to ../l