Subject: Re: [RFC PATCH v3 2/2] push: support pushing to a remote group

From: Junio C Hamano <[email-masked]>
Date: Wed, 25 Mar 2026 12:47:06 -0700

Usman Akinyemi <[email-masked]> writes:

> `git fetch` accepts a remote group name (configured via `remotes.<name>`
> in config) and fetches from each member remote. `git push` has no
> equivalent — it only accepts a single remote name.
>
> Teach `git push` to resolve its repository argument through
> `add_remote_or_group()`, which was made public in the previous patch,
> so that a user can push to all remotes in a group with:
>
>     git push <group>
>
> When the argument resolves to a single remote, the behaviour is
> identical to before. When it resolves to a group, each member remote
> is pushed in sequence.
>
> The group push path rebuilds the refspec list (`rs`) from scratch for
> each member remote so that per-remote push mappings configured via
> `remote.<name>.push` are resolved correctly against each specific
> remote. Without this, refspec entries would accumulate across iterations
> and each subsequent remote would receive a growing list of duplicated
> entries.
>
> Mirror detection (`remote->mirror`) is also evaluated per remote using
> a copy of the flags, so that a mirror remote in the group cannot set
> TRANSPORT_PUSH_FORCE on subsequent non-mirror remotes in the same group.
>
> Suggested-by: Junio C Hamano <[email-masked]>
> Signed-off-by: Usman Akinyemi <[email-masked]>
> ---
>  Documentation/git-push.adoc |  73 ++++++++++++++++--
>  builtin/push.c              | 123 +++++++++++++++++++++--------
>  t/meson.build               |   1 +
>  t/t5566-push-group.sh       | 150 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 306 insertions(+), 41 deletions(-)
>  create mode 100755 t/t5566-push-group.sh

> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index e5ba3a6742..b7f617a290 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -18,17 +18,28 @@ git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n

All the differences since the previous iteration in the patch to
this file makes sense to me, except one thing.

> +The behaviour upon failure depends on the kind of error encountered:
> +
> +If a member remote rejects the push, for example due to a
> +non-fast-forward update, force needed but not given, an existing tag,
> +or a server-side hook refusing a ref, Git reports the error and continues
> +pushing to the remaining remotes in the group. The overall exit code is
> +non-zero if any member push fails.
> +
> +If a member remote cannot be contacted at all, for example because the
> +repository does not exist, authentication fails, or the network is
> +unreachable, the push stops at that point and the remaining remotes
> +are not attempted.

I am not convinced that having these two "failure modes" is a good
thing; I am not convinced that a single failure mode is better,
either, though X-<.

I would personally have designed to mimic exactly like "git push r1;
git push r2; ..." would do (not concatenated with "&&" but with
";"), which would mean that there is only one single failure mode
that would not affect interactions with any other remotes, but I
have no strong arguments to choose that design, other than that it
would be easy to explain when we later start supporting pushes to
multiple remotes in parallel, where a failure to talk to one remote
cannot easily affect interaction with other remotes without getting
affected by timing issues.

> +This means the user is responsible for ensuring that the sequence of
> +individual pushes makes sense. If `git push r1`` would fail for a given
> +set of options and arguments, then `git push all-remotes` will fail in
> +the same way when it reaches r1. The group push does not do anything
> +special to make a failing individual push succeed.

"when it reaches r1" makes it sound as if the group push then stops
after that failure, but that is not what we just read in the two
paragraphs about two failure modes.