changeset 46778:066b8d8f75b8

push: allow to specify multiple destinations I end up needing that on a regular basis and it turn out to be very simple to implement. See documentation and test for details. Differential Revision: https://phab.mercurial-scm.org/D10161
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 10 Mar 2021 05:50:20 +0100
parents 25850879a215
children 49fd21f32695
files mercurial/commands.py tests/test-exchange-multi-source.t
diffstat 2 files changed, 227 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Wed Mar 17 15:20:45 2021 +0100
+++ b/mercurial/commands.py	Wed Mar 10 05:50:20 2021 +0100
@@ -5623,11 +5623,11 @@
         ),
     ]
     + remoteopts,
-    _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
+    _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
     helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
     helpbasic=True,
 )
-def push(ui, repo, dest=None, **opts):
+def push(ui, repo, *dests, **opts):
     """push changes to the specified destination
 
     Push changesets from the local repository to the specified
@@ -5663,6 +5663,9 @@
     Please see :hg:`help urls` for important details about ``ssh://``
     URLs. If DESTINATION is omitted, a default path will be used.
 
+    When passed multiple destinations, push will process them one after the
+    other, but stop should an error occur.
+
     .. container:: verbose
 
         The --pushvars option sends strings to the server that become
@@ -5706,7 +5709,12 @@
                 # if we try to push a deleted bookmark, translate it to null
                 # this lets simultaneous -r, -b options continue working
                 opts.setdefault(b'rev', []).append(b"null")
-    if True:
+
+    if not dests:
+        dests = [None]
+    some_pushed = False
+    result = 0
+    for dest in dests:
         path = ui.getpath(dest, default=(b'default-push', b'default'))
         if not path:
             raise error.ConfigError(
@@ -5753,9 +5761,9 @@
                 c = repo[b'.']
                 subs = c.substate  # only repos that are committed
                 for s in sorted(subs):
-                    result = c.sub(s).push(opts)
-                    if result == 0:
-                        return not result
+                    sub_result = c.sub(s).push(opts)
+                    if sub_result == 0:
+                        return 1
             finally:
                 del repo._subtoppath
 
@@ -5775,15 +5783,24 @@
                 opargs=opargs,
             )
 
-            result = not pushop.cgresult
+            if pushop.cgresult == 0:
+                result = 1
+            elif pushop.cgresult is not None:
+                some_pushed = True
 
             if pushop.bkresult is not None:
                 if pushop.bkresult == 2:
                     result = 2
                 elif not result and pushop.bkresult:
                     result = 2
+
+            if result:
+                break
+
         finally:
             other.close()
+    if result == 0 and not some_pushed:
+        result = 1
     return result
 
 
--- a/tests/test-exchange-multi-source.t	Wed Mar 17 15:20:45 2021 +0100
+++ b/tests/test-exchange-multi-source.t	Wed Mar 10 05:50:20 2021 +0100
@@ -71,6 +71,9 @@
 Test simple bare operation
 ==========================
 
+pull
+----
+
   $ hg clone main-repo test-repo-bare --rev 0 -U
   adding changesets
   adding manifests
@@ -121,9 +124,90 @@
   o  A 0
   
 
+push
+----
+
+  $ cp -R ./branch-E ./branch-E-push
+  $ cp -R ./branch-G ./branch-G-push
+  $ cp -R ./branch-H ./branch-H-push
+  $ hg push --force -R test-repo-bare ./branch-E-push ./branch-G-push ./branch-H-push
+  pushing to ./branch-E-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 3 changes to 3 files (+2 heads)
+  pushing to ./branch-G-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 4 files (+2 heads)
+  pushing to ./branch-H-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 4 files (+2 heads)
+  $ hg log -R ./branch-E-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 7
+  |
+  | o  E 4
+  | |
+  | o  D 3
+  |/
+  o  C 2
+  |
+  | o  G 6
+  | |
+  | o  F 5
+  |/
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-G-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 7
+  |
+  | o  E 6
+  | |
+  | o  D 5
+  |/
+  o  C 4
+  |
+  | o  G 3
+  | |
+  | o  F 2
+  |/
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-H-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  G 7
+  |
+  o  F 6
+  |
+  | o  E 5
+  | |
+  | o  D 4
+  | |
+  | | o  H 3
+  | |/
+  | o  C 2
+  |/
+  o  B 1
+  |
+  o  A 0
+  
+  $ rm -rf ./*-push
+
 Test operation with a target
 ============================
 
+pull
+----
+
   $ hg clone main-repo test-repo-rev --rev 0 -U
   adding changesets
   adding manifests
@@ -199,6 +283,125 @@
   o  A 0
   
 
+push
+----
+
+We only push a specific branch with --rev
+
+  $ cp -R ./branch-E ./branch-E-push
+  $ cp -R ./branch-G ./branch-G-push
+  $ cp -R ./branch-H ./branch-H-push
+  $ hg push --force -R test-repo-bare ./branch-E-push ./branch-G-push ./branch-H-push --rev default
+  pushing to ./branch-E-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pushing to ./branch-G-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files (+1 heads)
+  pushing to ./branch-H-push
+  searching for changes
+  no changes found
+  $ hg log -R ./branch-E-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 5
+  |
+  | o  E 4
+  | |
+  | o  D 3
+  |/
+  o  C 2
+  |
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-G-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 5
+  |
+  o  C 4
+  |
+  | o  G 3
+  | |
+  | o  F 2
+  |/
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-H-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 3
+  |
+  o  C 2
+  |
+  o  B 1
+  |
+  o  A 0
+  
+  $ rm -rf ./*-push
+
+Same push, but the first one is a no-op
+
+  $ cp -R ./branch-E ./branch-E-push
+  $ cp -R ./branch-G ./branch-G-push
+  $ cp -R ./branch-H ./branch-H-push
+  $ hg push --force -R test-repo-bare ./branch-G-push ./branch-H-push ./branch-E-push --rev default
+  pushing to ./branch-G-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files (+1 heads)
+  pushing to ./branch-H-push
+  searching for changes
+  no changes found
+  pushing to ./branch-E-push
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  $ hg log -R ./branch-E-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 5
+  |
+  | o  E 4
+  | |
+  | o  D 3
+  |/
+  o  C 2
+  |
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-G-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 5
+  |
+  o  C 4
+  |
+  | o  G 3
+  | |
+  | o  F 2
+  |/
+  o  B 1
+  |
+  o  A 0
+  
+  $ hg log -R ./branch-H-push -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
+  o  H 3
+  |
+  o  C 2
+  |
+  o  B 1
+  |
+  o  A 0
+  
+  $ rm -rf ./*-push
+
 
 Test with --update
 ==================