diff --git a/mercurial/commands.py b/mercurial/commands.py
index e41f6c2e69c43568c4d0d520b11407f2c5da2510_bWVyY3VyaWFsL2NvbW1hbmRzLnB5..9b8d1ad851f8c496204dff06026bf8e13813a4d6_bWVyY3VyaWFsL2NvbW1hbmRzLnB5 100644
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4497,6 +4497,7 @@
      _('a specific branch you would like to push'), _('BRANCH')),
     ('', 'new-branch', False, _('allow pushing a new branch')),
     ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
+    ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
     ] + remoteopts,
     _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
     helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
@@ -4614,6 +4615,7 @@
     pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
                            newbranch=opts.get('new_branch'),
                            bookmarks=opts.get('bookmark', ()),
+                           publish=opts.get('publish'),
                            opargs=opargs)
 
     result = not pushop.cgresult
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
index e41f6c2e69c43568c4d0d520b11407f2c5da2510_bWVyY3VyaWFsL2V4Y2hhbmdlLnB5..9b8d1ad851f8c496204dff06026bf8e13813a4d6_bWVyY3VyaWFsL2V4Y2hhbmdlLnB5 100644
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -359,7 +359,7 @@
     """
 
     def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
-                 bookmarks=(), pushvars=None):
+                 bookmarks=(), publish=False, pushvars=None):
         # repo we push from
         self.repo = repo
         self.ui = repo.ui
@@ -421,6 +421,8 @@
         self.pkfailcb = {}
         # an iterable of pushvars or None
         self.pushvars = pushvars
+        # publish pushed changesets
+        self.publish = publish
 
     @util.propertycache
     def futureheads(self):
@@ -478,7 +480,7 @@
 
 
 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
-         opargs=None):
+         publish=False, opargs=None):
     '''Push outgoing changesets (limited by revs) from a local
     repository to remote. Return an integer:
       - None means nothing to push
@@ -490,7 +492,7 @@
     if opargs is None:
         opargs = {}
     pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
-                           **pycompat.strkwargs(opargs))
+                           publish, **pycompat.strkwargs(opargs))
     if pushop.remote.local():
         missing = (set(pushop.repo.requirements)
                    - pushop.remote.local().supported)
@@ -630,7 +632,10 @@
     # XXX Beware that revset break if droots is not strictly
     # XXX root we may want to ensure it is but it is costly
     fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
-    if not outgoing.missing:
+    if not pushop.remotephases.publishing and pushop.publish:
+        future = list(unfi.set('%ln and (not public() or %ln::)',
+                               pushop.futureheads, droots))
+    elif not outgoing.missing:
         future = fallback
     else:
         # adds changeset we are going to push as draft
diff --git a/tests/test-completion.t b/tests/test-completion.t
index e41f6c2e69c43568c4d0d520b11407f2c5da2510_dGVzdHMvdGVzdC1jb21wbGV0aW9uLnQ=..9b8d1ad851f8c496204dff06026bf8e13813a4d6_dGVzdHMvdGVzdC1jb21wbGV0aW9uLnQ= 100644
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -325,7 +325,7 @@
   paths: template
   phase: public, draft, secret, force, rev
   pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
-  push: force, rev, bookmark, branch, new-branch, pushvars, ssh, remotecmd, insecure
+  push: force, rev, bookmark, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
   recover: 
   remove: after, force, subrepos, include, exclude, dry-run
   rename: after, force, include, exclude, dry-run
diff --git a/tests/test-phases-exchange.t b/tests/test-phases-exchange.t
index e41f6c2e69c43568c4d0d520b11407f2c5da2510_dGVzdHMvdGVzdC1waGFzZXMtZXhjaGFuZ2UudA==..9b8d1ad851f8c496204dff06026bf8e13813a4d6_dGVzdHMvdGVzdC1waGFzZXMtZXhjaGFuZ2UudA== 100644
--- a/tests/test-phases-exchange.t
+++ b/tests/test-phases-exchange.t
@@ -1559,3 +1559,194 @@
   |
   o  426ba public
   
+  $ killdaemons.py
+
+
+--publish flag
+--------------
+
+  $ hg init doesnt-publish
+  $ cd doesnt-publish
+  $ cat > .hg/hgrc << EOF
+  > [phases]
+  > publish=0
+  > EOF
+  $ mkcommit orig-root
+  test-debug-phase: new rev 0:  x -> 1
+  $ hg phase --public -r 'all()'
+  test-debug-phase: move rev 0: 1 -> 0
+  $ cd ..
+
+  $ hg clone -q doesnt-publish client
+  $ cd client
+
+pushing nothing
+
+  $ mkcommit new-A
+  test-debug-phase: new rev 1:  x -> 1
+  $ mkcommit new-B
+  test-debug-phase: new rev 2:  x -> 1
+  $ hg push --publish -r null
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  no changes found
+  [1]
+  $ hgph
+  @  2 draft new-B - 89512e87d697
+  |
+  o  1 draft new-A - 4826e44e690e
+  |
+  o  0 public orig-root - c48edaf99a10
+  
+
+pushing a new changeset (selective)
+
+  $ hg push --publish -r 'desc("new-A")'
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 1:  x -> 0
+  test-debug-phase: move rev 1: 1 -> 0
+  $ hgph
+  @  2 draft new-B - 89512e87d697
+  |
+  o  1 public new-A - 4826e44e690e
+  |
+  o  0 public orig-root - c48edaf99a10
+  
+
+pushing a new changeset (linear)
+
+  $ hg push --publish
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 2:  x -> 0
+  test-debug-phase: move rev 2: 1 -> 0
+  $ hgph
+  @  2 public new-B - 89512e87d697
+  |
+  o  1 public new-A - 4826e44e690e
+  |
+  o  0 public orig-root - c48edaf99a10
+  
+
+pushing new changesets (different branches)
+
+  $ mkcommit new-C
+  test-debug-phase: new rev 3:  x -> 1
+  $ hg update -q '.^'
+  $ hg branch -q another
+  $ mkcommit new-D
+  test-debug-phase: new rev 4:  x -> 1
+  $ hg push --new-branch --publish
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files (+1 heads)
+  test-debug-phase: new rev 3:  x -> 0
+  test-debug-phase: new rev 4:  x -> 0
+  test-debug-phase: move rev 3: 1 -> 0
+  test-debug-phase: move rev 4: 1 -> 0
+  $ hgph
+  @  4 public new-D - 5e53dcafd13c
+  |
+  | o  3 public new-C - 1665482cc06d
+  |/
+  o  2 public new-B - 89512e87d697
+  |
+  o  1 public new-A - 4826e44e690e
+  |
+  o  0 public orig-root - c48edaf99a10
+  
+
+pushing a shared changeset
+
+  $ mkcommit new-E
+  test-debug-phase: new rev 5:  x -> 1
+  $ hg push
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 5:  x -> 1
+  $ hg push --publish
+  pushing to $TESTTMP/doesnt-publish
+  searching for changes
+  no changes found
+  test-debug-phase: move rev 5: 1 -> 0
+  test-debug-phase: move rev 5: 1 -> 0
+  [1]
+  $ hgph
+  @  5 public new-E - 48931ee3529c
+  |
+  o  4 public new-D - 5e53dcafd13c
+  |
+  | o  3 public new-C - 1665482cc06d
+  |/
+  o  2 public new-B - 89512e87d697
+  |
+  o  1 public new-A - 4826e44e690e
+  |
+  o  0 public orig-root - c48edaf99a10
+  
+  $ cd ..
+
+--publish with subrepos (doesn't propagate to subrepos currently)
+
+  $ hg init with-subrepo
+  $ cd with-subrepo
+  $ cat > .hg/hgrc << EOF
+  > [phases]
+  > publish=0
+  > EOF
+  $ hg init subrepo
+  $ cd subrepo
+  $ cat > .hg/hgrc << EOF
+  > [phases]
+  > publish=0
+  > EOF
+  $ echo foo > foo
+  $ hg ci -qAm0
+  test-debug-phase: new rev 0:  x -> 1
+  $ cd ..
+  $ echo 'subrepo = subrepo' > .hgsub
+  $ hg add .hgsub
+  $ hg ci -m 'Adding subrepo'
+  test-debug-phase: new rev 0:  x -> 1
+  $ hgph
+  @  0 draft Adding subrepo - 74d5b62379c0
+  
+  $ hgph -R subrepo
+  @  0 draft 0 - 4b3f578e3344
+  
+  $ cd ..
+  $ hg clone with-subrepo client-with-subrepo
+  updating to branch default
+  cloning subrepo subrepo from $TESTTMP/with-subrepo/subrepo
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd client-with-subrepo
+  $ hg push --publish
+  pushing to $TESTTMP/with-subrepo
+  no changes made to subrepo subrepo since last push to $TESTTMP/with-subrepo/subrepo
+  searching for changes
+  no changes found
+  test-debug-phase: move rev 0: 1 -> 0
+  test-debug-phase: move rev 0: 1 -> 0
+  [1]
+  $ hgph
+  @  0 public Adding subrepo - 74d5b62379c0
+  
+  $ hgph -R subrepo
+  @  0 draft 0 - 4b3f578e3344
+