changeset 46931:d4e4ccb75f99

outgoing: accept multiple destinations This align the behavior of `hg outgoing` with the one of `hg incoming`. In addition this prepare the introduction of having simple `path` resolve to multiple destination in practice (eg: `default`) Differential Revision: https://phab.mercurial-scm.org/D10391
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 14 Apr 2021 01:26:44 +0200
parents 0afe96e374a7
children dec31caf5fd6
files mercurial/commands.py mercurial/hg.py tests/test-exchange-multi-source.t
diffstat 3 files changed, 143 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Thu Apr 15 09:23:28 2021 +0200
+++ b/mercurial/commands.py	Wed Apr 14 01:26:44 2021 +0200
@@ -4923,10 +4923,10 @@
     + logopts
     + remoteopts
     + subrepoopts,
-    _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
+    _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
     helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
 )
-def outgoing(ui, repo, dest=None, **opts):
+def outgoing(ui, repo, *dests, **opts):
     """show changesets not found in the destination
 
     Show changesets not found in the specified destination repository
@@ -4962,30 +4962,24 @@
 
     Returns 0 if there are outgoing changes, 1 otherwise.
     """
-    # hg._outgoing() needs to re-resolve the path in order to handle #branch
-    # style URLs, so don't overwrite dest.
-    path = ui.getpath(dest, default=(b'default-push', b'default'))
-    if not path:
-        raise error.ConfigError(
-            _(b'default repository not configured!'),
-            hint=_(b"see 'hg help config.paths'"),
-        )
-
     opts = pycompat.byteskwargs(opts)
     if opts.get(b'bookmarks'):
-        dest = path.pushloc or path.loc
-        other = hg.peer(repo, opts, dest)
-        try:
-            if b'bookmarks' not in other.listkeys(b'namespaces'):
-                ui.warn(_(b"remote doesn't support bookmarks\n"))
-                return 0
-            ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest))
-            ui.pager(b'outgoing')
-            return bookmarks.outgoing(ui, repo, other)
-        finally:
-            other.close()
-
-    return hg.outgoing(ui, repo, dest, opts)
+        for path in urlutil.get_push_paths(repo, ui, dests):
+            dest = path.pushloc or path.loc
+            other = hg.peer(repo, opts, dest)
+            try:
+                if b'bookmarks' not in other.listkeys(b'namespaces'):
+                    ui.warn(_(b"remote doesn't support bookmarks\n"))
+                    return 0
+                ui.status(
+                    _(b'comparing with %s\n') % urlutil.hidepassword(dest)
+                )
+                ui.pager(b'outgoing')
+                return bookmarks.outgoing(ui, repo, other)
+            finally:
+                other.close()
+
+    return hg.outgoing(ui, repo, dests, opts)
 
 
 @command(
--- a/mercurial/hg.py	Thu Apr 15 09:23:28 2021 +0200
+++ b/mercurial/hg.py	Wed Apr 14 01:26:44 2021 +0200
@@ -1320,51 +1320,53 @@
     return _incoming(display, subreporecurse, ui, repo, source, opts)
 
 
-def _outgoing(ui, repo, dest, opts, subpath=None):
-    path = ui.getpath(dest, default=(b'default-push', b'default'))
-    if not path:
-        raise error.Abort(
-            _(b'default repository not configured!'),
-            hint=_(b"see 'hg help config.paths'"),
-        )
-    dest = path.pushloc or path.loc
-    if subpath is not None:
-        subpath = urlutil.url(subpath)
-        if subpath.isabs():
-            dest = bytes(subpath)
-        else:
-            p = urlutil.url(dest)
-            p.path = os.path.normpath(b'%s/%s' % (p.path, subpath))
-            dest = bytes(p)
+def _outgoing(ui, repo, dests, opts, subpath=None):
+    out = set()
+    others = []
+    for path in urlutil.get_push_paths(repo, ui, dests):
+        dest = path.pushloc or path.loc
+        if subpath is not None:
+            subpath = urlutil.url(subpath)
+            if subpath.isabs():
+                dest = bytes(subpath)
+            else:
+                p = urlutil.url(dest)
+                p.path = os.path.normpath(b'%s/%s' % (p.path, subpath))
+                dest = bytes(p)
+        branches = path.branch, opts.get(b'branch') or []
 
-    branches = path.branch, opts.get(b'branch') or []
-
-    ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest))
-    revs, checkout = addbranchrevs(repo, repo, branches, opts.get(b'rev'))
-    if revs:
-        revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)]
+        ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest))
+        revs, checkout = addbranchrevs(repo, repo, branches, opts.get(b'rev'))
+        if revs:
+            revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)]
 
-    other = peer(repo, opts, dest)
-    try:
-        outgoing = discovery.findcommonoutgoing(
-            repo, other, revs, force=opts.get(b'force')
-        )
-        o = outgoing.missing
-        if not o:
-            scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
-        return o, other
-    except:  # re-raises
-        other.close()
-        raise
+        other = peer(repo, opts, dest)
+        try:
+            outgoing = discovery.findcommonoutgoing(
+                repo, other, revs, force=opts.get(b'force')
+            )
+            o = outgoing.missing
+            out.update(o)
+            if not o:
+                scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
+            others.append(other)
+        except:  # re-raises
+            other.close()
+            raise
+    # make sure this is ordered by revision number
+    outgoing_revs = list(out)
+    cl = repo.changelog
+    outgoing_revs.sort(key=cl.rev)
+    return outgoing_revs, others
 
 
-def _outgoing_recurse(ui, repo, dest, opts):
+def _outgoing_recurse(ui, repo, dests, opts):
     ret = 1
     if opts.get(b'subrepos'):
         ctx = repo[None]
         for subpath in sorted(ctx.substate):
             sub = ctx.sub(subpath)
-            ret = min(ret, sub.outgoing(ui, dest, opts))
+            ret = min(ret, sub.outgoing(ui, dests, opts))
     return ret
 
 
@@ -1391,10 +1393,10 @@
         yield n
 
 
-def outgoing(ui, repo, dest, opts, subpath=None):
+def outgoing(ui, repo, dests, opts, subpath=None):
     if opts.get(b'graph'):
         logcmdutil.checkunsupportedgraphflags([], opts)
-    o, other = _outgoing(ui, repo, dest, opts, subpath=subpath)
+    o, others = _outgoing(ui, repo, dests, opts, subpath=subpath)
     ret = 1
     try:
         if o:
@@ -1415,11 +1417,13 @@
                 for n in _outgoing_filter(repo, o, opts):
                     displayer.show(repo[n])
                 displayer.close()
-        cmdutil.outgoinghooks(ui, repo, other, opts, o)
-        ret = min(ret, _outgoing_recurse(ui, repo, dest, opts))
+        for oth in others:
+            cmdutil.outgoinghooks(ui, repo, oth, opts, o)
+            ret = min(ret, _outgoing_recurse(ui, repo, dests, opts))
         return ret  # exit code is zero since we found outgoing changes
     finally:
-        other.close()
+        for oth in others:
+            oth.close()
 
 
 def verify(repo, level=None):
--- a/tests/test-exchange-multi-source.t	Thu Apr 15 09:23:28 2021 +0200
+++ b/tests/test-exchange-multi-source.t	Wed Apr 14 01:26:44 2021 +0200
@@ -130,6 +130,46 @@
   $ cp -R ./branch-E ./branch-E-push
   $ cp -R ./branch-G ./branch-G-push
   $ cp -R ./branch-H ./branch-H-push
+  $ hg out -G -R test-repo-bare ./branch-E-push ./branch-G-push ./branch-H-push
+  comparing with ./branch-E-push
+  searching for changes
+  comparing with ./branch-G-push
+  searching for changes
+  comparing with ./branch-H-push
+  searching for changes
+  o  changeset:   7:40faebb2ec45
+  |  tag:         tip
+  |  parent:      2:f838bfaca5c7
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     H
+  |
+  | o  changeset:   6:c521a06b234b
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     G
+  | |
+  | o  changeset:   5:2f3a4c5c1417
+  |    parent:      1:27547f69f254
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     F
+  |
+  | o  changeset:   4:a603bfb5a83e
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     E
+  | |
+  | o  changeset:   3:b3325c91a4d9
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     D
+  |
+  o  changeset:   2:f838bfaca5c7
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     C
+  
   $ hg push --force -R test-repo-bare ./branch-E-push ./branch-G-push ./branch-H-push
   pushing to ./branch-E-push
   searching for changes
@@ -291,6 +331,26 @@
   $ cp -R ./branch-E ./branch-E-push
   $ cp -R ./branch-G ./branch-G-push
   $ cp -R ./branch-H ./branch-H-push
+  $ hg out -G -R test-repo-bare ./branch-E-push ./branch-G-push ./branch-H-push --rev default
+  comparing with ./branch-E-push
+  searching for changes
+  comparing with ./branch-G-push
+  searching for changes
+  comparing with ./branch-H-push
+  searching for changes
+  no changes found
+  o  changeset:   7:40faebb2ec45
+  |  tag:         tip
+  |  parent:      2:f838bfaca5c7
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     H
+  |
+  o  changeset:   2:f838bfaca5c7
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     C
+  
   $ 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
@@ -349,6 +409,26 @@
   $ cp -R ./branch-E ./branch-E-push
   $ cp -R ./branch-G ./branch-G-push
   $ cp -R ./branch-H ./branch-H-push
+  $ hg out -G -R test-repo-bare ./branch-G-push ./branch-H-push ./branch-E-push --rev default
+  comparing with ./branch-G-push
+  searching for changes
+  comparing with ./branch-H-push
+  searching for changes
+  no changes found
+  comparing with ./branch-E-push
+  searching for changes
+  o  changeset:   7:40faebb2ec45
+  |  tag:         tip
+  |  parent:      2:f838bfaca5c7
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     H
+  |
+  o  changeset:   2:f838bfaca5c7
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     C
+  
   $ 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