GorvGoyl
GorvGoyl

Reputation: 49160

How do I store credentials per repository in Git Credential Manager for Windows?

I have two GitHub accounts, work and personal, for which I want to securely store credentials in Windows 10.

git config --global credential.helper manager only sets a single username and password, which conflicts between a repository from my personal account and one from my work account. Both repositories are cloned using HTTPS.

I want to store and access different credentials, probably based on repository username. Is it possible?

I know SSH is an option, but I would like to know how to do it for HTTPS.

Upvotes: 23

Views: 30091

Answers (4)

Michael come lately
Michael come lately

Reputation: 9323

There are three different ways you can do this, depending on your particular goals and circumstances:

  • Put a username in the URL.
  • Enable useHttpPath.
  • Switch to SSH on port 443.

Add your username in the URL

On GitHub, you can add a username to the HTTPS URL of your remote:

State Remote URL
Before https://github.com/path/repo.git
After https://JerryGoyal@github.com/path/repo.git

Since the the part of the URL used for comparison is different, you can add both your work and personal forks as remotes for the same repository if you want to. The technique works on many repository hosts, but some may not support it.

Host Support Source
GitHub Stack Overflow
Bitbucket Tested
GitLab Stack Overflow
Codeberg / Forgejo Stack Overflow
Gitea Issue 2681, Issue 10381
Gitee ???
SourceHut No1 Mailing list
cgit No? Gitea issue 18166

1 SourceHut only allows Git access over SSH.

Set useHttpPath for the host

Git Credential Manager can select a credential based on the full URL, rather than sharing them by hostname.

credential.useHttpPath

Tells Git to pass the entire repository URL, rather than just the hostname, when calling out to a credential provider. (This setting comes from Git itself, not GCM.)

Defaults to false.

This second method does not work if you want to use multiple remote credentials for the exact same remote. But if you have different URLs for separate remotes, it should work fine, even from a single local repository.

All repositories on the remote host

This is often the most useful mode for useHttpPath. To set the option for all GitHub remote URLs, run this:

git config --global credential.https://github.com.useHttpPath true

Git for Windows enables useHttpPath for Azure Repos right out of the box. You can see it for yourself in etc/gitconfig in your install location.

[credential "https://dev.azure.com"]
    useHttpPath = true

Just one repository on the remote host

As rjmunro notes, you can drop --global to use the path for only the current repository. If so, you may as well drop the hostname, too:

git config credential.useHttpPath true

Then, repositories for the host will default to a shared host-credential, but this repository will use the full URL path for saving and loading its credential.

All repositories on your computer

Technically, you can force yourself to separately add credentials for every single remote repository. That's needlessly verbose, but this answer shows how:

git config --global credential.useHttpPath true

What I really want is ssh, but Port 22 is blocked

If you're only asking about HTTPS because you have a firewall problem outside of your control, you might be interested in my answer to a similar question for using Port 443 for certain Git providers that support it.

Upvotes: 25

rbennett485
rbennett485

Reputation: 2163

You could do it with a different helper e.g. git-credential-store, which takes an optional parameter for a credential file path. You could set this in the local configuration in each repository, with a different credentials file for each one.

Alternatively, use the suggestion in the link in phd's comment which should work for Git Credential Manager For Windows.

Upvotes: 1

VonC
VonC

Reputation: 1323523

More generally, you can use credential.useHttpPath to split credential management for multiple repositories run by the same host. []

In that case, use Git 2.27 (Q2 2020), because the parsing of URL for the credential helper has been corrected.

See commit 4c5971e (14 Apr 2020) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit a397e9c, 22 Apr 2020)

credential: treat "?" and "#" in URLs as end of host

Signed-off-by: Jeff King

It's unusual to see:

https://example.com?query-parameters

without an intervening slash, like:

https://example.com/some-path?query-parameters

or even:

https://example.com/?query-parameters

but it is a valid end to the hostname (actually "authority component") according to RFC 3986. Likewise for "#".

And curl will parse the URL according to the standard, meaning it will contact example.com, but our credential code would ask about a bogus hostname with a "?" in it.

Let's make sure we follow the standard, and more importantly ask about the same hosts that curl will be talking to.

It would be nice if we could just ask curl to parse the URL for us. But it didn't grow a URL-parsing API until 7.62, so we'd be stuck with fallback code either way. Plus we'd need this code in the main Git binary, where we've tried to avoid having a link dependency on libcurl.

But let's at least fix our parser. Moving to curl's parser would prevent other potential discrepancies, but this gives us immediate relief for the known problem, and would help our fallback code if we eventually use curl.


With Git 2.35 (Q1 2022), credentials and other variable value benefit from the latest of RFC 3986: treating underscores (_) as any other URL-valid characters in an URL when matching the per-URL configuration variable names.

See commit e4c497a (12 Oct 2021) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 96eca02, 29 Nov 2021)

urlmatch: add underscore to URL_HOST_CHARS

Reported-by: Alex Waite
Signed-off-by: Jeff King

When parsing a URL to normalize it, we allow hostnames to contain only dot (".") or dash ("-"), plus brackets and colons for IPv6 literals. This matches the old URL standard in RFC 1738, which says:

host           = hostname | hostnumber
hostname       = *[ domainlabel "." ] toplabel
domainlabel    = alphadigit | alphadigit *[ alphadigit | "-" ] alphadigit

But this was later updated by RFC 3986, which is more liberal:

host        = IP-literal / IPv4address / reg-name
reg-name    = *( unreserved / pct-encoded / sub-delims )
unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

While names with underscore in them are not common and possibly violate some DNS rules, they do work in practice, and we will happily contact them over http://, git://, or ssh://. It seems odd to ignore them for purposes of URL matching, especially when the URL RFC seems to allow them.

There shouldn't be any downside here. It's not a syntactically significant character in a URL, so we won't be confused about parsing; we'd have simply rejected such a URL previously (the test here checks the url code directly, but the obvious user-visible effect would be failing to match credential.http://foo_bar.example.com.helper, or similar config in http.<url>.*).

Arguably we'd want to allow tilde ("~") here, too. There's likewise probably no downside, but I didn't add it simply because it seems like an even less likely character to appear in a hostname.

Upvotes: 2

dgarg
dgarg

Reputation: 76

You can't have multiple usernames per host (or URI). As far as I know, SSH is the most straight-forward, as it currently stands, to do what you want to do.

For more information, you can look at VonC's answer to a very similar question as yours. GitHub: Separate credentials for two accounts on Windows

Upvotes: -5

Related Questions