'Always pull using HTTPS, push using SSH, using insteadOf?
I have a number of repositories using different Github URL formats. I would like all repositories to always fetch from Github over HTTPS, and to push over SSH. This makes my life easier, with ssh keys / agent forwarding /...
This would make sense to me, but it doesn't rewrite a couple of cases:
[url "[email protected]:"]
pushInsteadOf = "https://github.com/"
[url "https://github.com/"]
insteadOf = "[email protected]:"
e.g., for a test repository with three remotes:
- hh: http fetch, http push
- hs: http fetch, ssh push
- sh: ssh fetch, http push
That is:
% git remote -v
hh https://github.com/foo/bar (fetch)
hh https://github.com/foo/bar (push)
hs https://github.com/foo/bar (fetch)
hs [email protected]:foo/bar (push)
sh [email protected]:foo/bar (fetch)
sh https://github.com/foo/bar (push)
...this config generates:
% cat .gitconfig
[url "[email protected]:"]
pushInsteadOf = "https://github.com/"
[url "https://github.com/"]
insteadOf = "[email protected]:"
% HOME=. git remote -v
hh https://github.com/foo/bar (fetch)
hh [email protected]:foo/bar (push)
hs https://github.com/foo/bar (fetch)
hs https://github.com/foo/bar (push) # wrong
sh https://github.com/foo/bar (fetch)
sh https://github.com/foo/bar (push) # wrong
What git config snippet will generate the "http fetch, ssh push" remotes I want in all cases?
Solution 1:[1]
This would make sense to me, but it doesn't rewrite a couple of cases
If you have an explicitly configured push URL for a repository then you cannot override it with pushInsteadOf
. Refer to the documentation:
url.<base>.pushInsteadOf
Any URL that starts with this value will not be pushed to; instead, it will be rewritten to start with
<base>
, and the resulting URL will be pushed to. In cases where some site serves a large number of repositories, and serves them with multiple access methods, some of which do not allow push, this feature allows people to specify a pull-only URL and have Git automatically use an appropriate URL to push, even for a never-before-seen repository on the site. When more than onepushInsteadOf
strings match a given URL, the longest match is used. If a remote has an explicit pushurl, Git will ignore this setting for that remote.
Note that the url.<base>.insteadOf
setting is applied unconditionally, which explains why your SSH push URL (for the hs
remote) was replaced with an HTTPS URL:
url.<base>.insteadOf
Any URL that starts with this value will be rewritten to start, instead, with
<base>
. In cases where some site serves a large number of repositories, and serves them with multiple access methods, and some users need to use different access methods, this feature allows people to specify any of the equivalent URLs and have Git automatically rewrite the URL to the best alternative for the particular user, even for a never-before-seen repository on the site. When more than oneinsteadOf
strings match a given URL, the longest match is used.
So, to achieve your goal you must
remove the
url.<base>.insteadOf
setting from your git config file(s).individually set fetch/pull and/or push URLs for all your remotes that deviate from your desired scheme.
Solution 2:[2]
Try using:
[url "https://github.com/"]
insteadOf = "[email protected]:"
[url "[email protected]:"]
pushInsteadOf = "https://github.com/"
pushInsteadOf = "[email protected]:"
This will force all pulls to use HTTPS, and pushes to use SSH. The second pushInsteadOf
is a little nonsensical, as it rewrites a [email protected]:
to the same [email protected]:
. But, this prevents the insteadOf
from rewritting the [email protected]:
to https://github.com/
for pushes.
With this:
# initial: [email protected]:git/git.git
git remote -v
origin https://github.com/git/git.git (fetch)
origin [email protected]:git/git.git (push)
# initial: https://github.com/git/git.git
git remote -v
origin https://github.com/git/git.git (fetch)
origin [email protected]:git/git.git (push)
The important part is that pushInsteadOf
rewrites push URLs first, and if theres a match it prevents an insteadOf
from rewritting. By making [email protected]:
-> [email protected]:
, we've locked in the push URL. The regular pushInsteadOf
will still rewrite an initial HTTPS into SSH for pushes, and the insteadOf
will still rewrite a SSH into HTTPS for pulls.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | jridgewell |