Is there a easy way for a script to detect if a remote already exists and add it only if it doesn't? A plumbing command or porcelain flag?
When running git remote add foo https://example.net
with an existing remote I get:
fatal: remote foo already exists.
Ideally there would be a flag such as --if-not-exists
or --update-if-exists
but I couldn't find any in the documentation.
I'm thinking of grepping the output of git remote
but is there a better way?
git config remote.foo.url >&- || git remote add foo
git's written to handle closed fd's so you don't need >/dev/null
, just close it, config sets a return code when you ask for a nonexistent config.
Another answer suggested in 2019:
If the remote already exist:
$ git remote add foo https://example.net fatal: remote foo already exists. $ echo $? 128
That does change with Git 2.30 (Q1 2021): exit codes from "git remote add/rename
"(man)
were not usable by scripted callers.
See commit 9144ba4 (27 Oct 2020) by Ævar Arnfjörð Bjarmason (avar
).
(Merged by Junio C Hamano -- gitster
-- in commit ecf95d9, 09 Nov 2020)
remote
: add meaningful exit code on missing/existingSigned-off-by: Ævar Arnfjörð Bjarmason
Change the exit code for the likes of "
git remote add/rename
"(man) to exit with 2 if the remote in question doesn't exist, and 3 if it does. Before we'd justdie()
and exit with the general 128 exit code.This changes the output message from e.g.:
fatal: remote origin already exists.
To:
error: remote origin already exists.
Which I believe is a feature, since we generally use "fatal" for the generic errors, and "error" for the more specific ones with a custom exit code, but this part of the change may break code that already relies on stderr parsing (not that we ever supported that...).
The motivation for this is a discussion around some code in GitLab's gitaly which wanted to check this, and had to parse stderr to do so: https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2695
It's worth noting as an aside that a method of checking this that doesn't rely on that is to check with "
git config
"(man) whether the value in question does or doesn't exist. That introduces aTOCTOU
race condition, but on the other hand this code (e.g. "git remote add
(man)) already has aTOCTOU
race.We go through the config.lock for the actual setting of the config, but the pseudocode logic is:
read_config(); check_config_and_arg_sanity(); save_config();
So e.g. if a
sleep()
is added right after theremote_is_configured()
check inadd()
we'll clobberremote.NAME.url
, and add another (usually duplicate)remote.NAME.fetch
entry (and other values, depending on invocation).
git remote
now includes in its man page:
EXIT STATUS
On success, the exit status is
0
.When subcommands such as '
add
', 'rename
', and 'remove
' can't find the remote in question, the exit status is2
.
When the remote already exists, the exit status is3
.On any other error, the exit status may be any other non-zero value.
Use git remote show <remote>
:
$ git remote show origin && echo ok || echo err
* remote origin
Fetch URL: …
Push URL: …
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master rebases onto remote master
Local ref configured for 'git push':
master pushes to master (up to date)
ok
$ git remote show xxx && echo ok || echo err
fatal: 'xxx' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
err
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With