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 $errThere'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