git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Git multiple remotes push stop at first failed connection

From
Jeff King <peff@peff.net>
Date
Jun 1, 2020, 21:40 UTC
Message-ID
<20200601214003.GA3309882@coredump.intra.peff.net>
In-Reply-To
<CAGKX4vGhTbEqZS9+iYA2wZWRRaddQC6O4KV+zLaNYKkZgN36Xg@mail.gmail.com>
On Sun, May 31, 2020 at 08:28:38PM -0400, John Siu wrote:
Show 9 quoted lines
> Let say my project has following remotes:
> 
> $ git remote -v
> git.all "server A git url" (fetch)
> git.all "server A git url" (push)
> git.all "server B git url" (push)
> git.all "server C git ur" (push)
> 
> When all serverA/B/C are online, "git push" works.

A slight nomenclature nit, but that's _one_ remote that has several push urls.

Show 10 quoted lines
> However "git push" will stop at the first server it failed to connect.
> So if git cannot connect to server A, it will not continue with server
> B/C.
> 
> In the past I have server C turn off from time to time, so failing the
> last push is expected. However recently server A went offline
> completely and we notice git is not pushing to the remaining 2
> remotes.
> 
> Not sure if this is intended behavior or can be improved.

I don't think we've ever documented the error-handling semantics. Looking at the relevant code in builtin/push.c:do_push():

          url_nr = push_url_of_remote(remote, &url);
          if (url_nr) {
                  for (i = 0; i < url_nr; i++) {
                          struct transport *transport =
                                  transport_get(remote, url[i]);
                          if (flags & TRANSPORT_PUSH_OPTIONS)
                                  transport->push_options = push_options;
                          if (push_with_options(transport, push_refspec, flags))
                                  errs++;
                  }
          } else {
                  struct transport *transport =
                          transport_get(remote, NULL);
                  if (flags & TRANSPORT_PUSH_OPTIONS)
                          transport->push_options = push_options;
                  if (push_with_options(transport, push_refspec, flags))
                          errs++;
          }
          return !!errs;

it does seem to try each one and collect the errors. But the underlying transport code is so ready to die() on errors, taking down the whole process, that I suspect it rarely manages to do so. You're probably much better off defining a separate remote for each push destination, then running your own shell loop:

  err=0
  for dst in serverA serverB serverC; do
    git push $dst || err=1
  done
  exit $err

There's really no benefit to doing it all in a single Git process, as we'd connect to each independently, run a separate independent pack-objects for each, etc.

I'd even suggest that Git implement such a loop itself, as we did for "git fetch --all", but sadly "push --all" is already taken for a different meaning (but it might still be worth doing under a different option name).

-Peff
Previous: John SiuNext: John Siu
Message 2 of 5 in “Git multiple remotes push stop at first failed connection”
  1. John SiuJun 1, 2020
  2. Jeff KingJun 1, 2020
  3. John SiuJun 2, 2020
  4. Junio C HamanoJun 2, 2020
  5. John SiuJun 2, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.