@@ -552,12 +552,13 @@ int cmd_push(int argc,
552552 int flags = 0 ;
553553 int tags = 0 ;
554554 int push_cert = -1 ;
555- int rc ;
555+ int rc = 0 ;
556+ int base_flags ;
556557 const char * repo = NULL ; /* default repository */
557558 struct string_list push_options_cmdline = STRING_LIST_INIT_DUP ;
559+ struct string_list remote_group = STRING_LIST_INIT_DUP ;
558560 struct string_list * push_options ;
559561 const struct string_list_item * item ;
560- struct remote * remote ;
561562
562563 struct option options [] = {
563564 OPT__VERBOSITY (& verbosity ),
@@ -620,39 +621,45 @@ int cmd_push(int argc,
620621 else if (recurse_submodules == RECURSE_SUBMODULES_ONLY )
621622 flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY ;
622623
623- if (tags )
624- refspec_append (& rs , "refs/tags/*" );
625-
626624 if (argc > 0 )
627625 repo = argv [0 ];
628626
629- remote = pushremote_get (repo );
630- if (!remote ) {
631- if (repo )
632- die (_ ("bad repository '%s'" ), repo );
633- die (_ ("No configured push destination.\n"
634- "Either specify the URL from the command-line or configure a remote repository using\n"
635- "\n"
636- " git remote add <name> <url>\n"
637- "\n"
638- "and then push using the remote name\n"
639- "\n"
640- " git push <name>\n" ));
641- }
642-
643- if (argc > 0 )
644- set_refspecs (argv + 1 , argc - 1 , remote );
645-
646- if (remote -> mirror )
647- flags |= (TRANSPORT_PUSH_MIRROR |TRANSPORT_PUSH_FORCE );
648-
649- if (flags & TRANSPORT_PUSH_ALL ) {
650- if (argc >= 2 )
651- die (_ ("--all can't be combined with refspecs" ));
652- }
653- if (flags & TRANSPORT_PUSH_MIRROR ) {
654- if (argc >= 2 )
655- die (_ ("--mirror can't be combined with refspecs" ));
627+ if (repo ) {
628+ if (!add_remote_or_group (repo , & remote_group )) {
629+ /*
630+ * Not a configured remote name or group name.
631+ * Try treating it as a direct URL or path, e.g.
632+ * git push /tmp/foo.git
633+ * git push https://github.com/user/repo.git
634+ * pushremote_get() creates an anonymous remote
635+ * from the URL so the loop below can handle it
636+ * identically to a named remote.
637+ */
638+ struct remote * r = pushremote_get (repo );
639+ if (!r )
640+ die (_ ("bad repository '%s'" ), repo );
641+ string_list_append (& remote_group , r -> name );
642+ }
643+ } else {
644+ struct remote * r = pushremote_get (NULL );
645+ if (!r )
646+ die (_ ("No configured push destination.\n"
647+ "Either specify the URL from the command-line or configure a remote repository using\n"
648+ "\n"
649+ " git remote add <name> <url>\n"
650+ "\n"
651+ "and then push using the remote name\n"
652+ "\n"
653+ " git push <name>\n"
654+ "\n"
655+ "To push to multiple remotes at once, configure a remote group using\n"
656+ "\n"
657+ " git config remotes.<groupname> \"<remote1> <remote2>\"\n"
658+ "\n"
659+ "and then push using the group name\n"
660+ "\n"
661+ " git push <groupname>\n" ));
662+ string_list_append (& remote_group , r -> name );
656663 }
657664
658665 if (!is_empty_cas (& cas ) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES ))
@@ -662,10 +669,60 @@ int cmd_push(int argc,
662669 if (strchr (item -> string , '\n' ))
663670 die (_ ("push options must not have new line characters" ));
664671
665- rc = do_push (flags , push_options , remote );
672+ /*
673+ * Push to each remote in remote_group. For a plain "git push <remote>"
674+ * or a default push, remote_group has exactly one entry and the loop
675+ * runs once — there is nothing structurally special about that case.
676+ * For a group, the loop runs once per member remote.
677+ *
678+ * Mirror detection and the --mirror/--all + refspec conflict checks
679+ * are done per remote inside the loop. A remote configured with
680+ * remote.NAME.mirror=true implies mirror mode for that remote only —
681+ * other non-mirror remotes in the same group are unaffected.
682+ *
683+ * rs is rebuilt from scratch for each remote so that per-remote push
684+ * mappings (remote.NAME.push config) are resolved against the correct
685+ * remote. iter_flags is derived from a clean snapshot of flags taken
686+ * before the loop so that a mirror remote cannot bleed
687+ * TRANSPORT_PUSH_FORCE into subsequent non-mirror remotes in the
688+ * same group.
689+ */
690+ base_flags = flags ;
691+ for (size_t i = 0 ; i < remote_group .nr ; i ++ ) {
692+ int iter_flags = base_flags ;
693+ struct remote * r = pushremote_get (remote_group .items [i ].string );
694+ if (!r )
695+ die (_ ("no such remote or remote group: %s" ),
696+ remote_group .items [i ].string );
697+
698+ if (r -> mirror )
699+ iter_flags |= (TRANSPORT_PUSH_MIRROR |TRANSPORT_PUSH_FORCE );
700+
701+ if (iter_flags & TRANSPORT_PUSH_ALL ) {
702+ if (argc >= 2 )
703+ die (_ ("--all can't be combined with refspecs" ));
704+ }
705+ if (iter_flags & TRANSPORT_PUSH_MIRROR ) {
706+ if (argc >= 2 )
707+ die (_ ("--mirror can't be combined with refspecs" ));
708+ }
709+
710+ refspec_clear (& rs );
711+ rs = (struct refspec ) REFSPEC_INIT_PUSH ;
712+
713+ if (tags )
714+ refspec_append (& rs , "refs/tags/*" );
715+ if (argc > 0 )
716+ set_refspecs (argv + 1 , argc - 1 , r );
717+
718+ rc |= do_push (iter_flags , push_options , r );
719+ }
720+
666721 string_list_clear (& push_options_cmdline , 0 );
667722 string_list_clear (& push_options_config , 0 );
723+ string_list_clear (& remote_group , 0 );
668724 clear_cas_option (& cas );
725+
669726 if (rc == -1 )
670727 usage_with_options (push_usage , options );
671728 else
0 commit comments