When you are working with multiple Git accounts across different git-providers it’s hard to manage access to all these repositories. When you search for a solution you will find different ways to solve this problem.
Basically it comes down to two SSH-based solutions;
- Use named SSH configurations in the
~/.ssh/config
file. - Use the git
includeIf
directive.
Both methods will be explained in detail but before we dive into each method I first want to set a baseline on the SSH-keys.
SSH-keys
Each method relies on the SSH-keys being uploaded to your git-provider (.pub only please!). The upload process is different for each provider.
The SSH-keys are stored by default in the directory ~/.ssh/
.
The naming convention used for the SSH-keys is [git-user.name]@[git-provider].ed25519
.
- git-user.name, the user name at your git provider.
- git-provider, the name of the git provider, including domain to separate possible internal and external git providers.
- ed25519, instead of the default RSA key I use Ed255191
The command to create the SSH-key pair:
syntax
ssh-keygen -t ed25519 -f ~/.ssh/[git-user.name]@[git-provider].ed25519 -C "[git-user.name]@[computer-name]"
example
ssh-keygen -t ed25519 -f ~/.ssh/tisgoed@github.com.ed25519 -C "tisgoed@MacFlurry"
As best practice add a comment ('-C' argument) with your git-user.name and the computer-name. It helps to identify the SSH-keys at your git-provider.
I re-use my SSH-keys for a specific git account per computer but not shared across computers. If for some reason your workstation is no longer available, you can identify and disable the SSH-keys at your git-provider.
Method 1: Use named SSH configurations
In this method a “named” entry is created in the .ssh/config
file. The entry content refers to the git-provider specific SSH-keys. The name of the entry is used in the git configuration’s remote origin
.
This method gives you full flexibility on the location of your local repositories.
Diagram for the named SSH configuration flow
The following diagram describes the configuration for a new git account:
The basic steps to set up a new git-provider:
- Create SSH-keys
- Add the named SSH-section
- Set the remote origin
The baseline for setting the SSH-keys is already described in the second paragraph. Moving on to step 2.
Step 2: Add a named SSH-section
For this step you need to modify the SSH-configuration file (~/.ssh/config
).
See the template and example of the named section below on what to add for your new git-provider.
A template of a named (git account) section in the ~/.ssh/config
file:
...
# GitProvider description [your git-user.name] account
Host [git-user.name]-[git-provider]
HostName [git-provider]
user git
IdentityFile ~/.ssh/[git-user.name]@[git-provider].ed25519
IdentitiesOnly yes
...
An example of two fictional named sections in the ~/.ssh/config
file:
...
# tisgoed @ GitHub.com
Host tisgoed-github.com
HostName github.com
user git
IdentityFile ~/.ssh/tisgoed@github.com.ed25519
IdentitiesOnly yes
# tisgoed @ BitBucket.com
Host tisgoed-bitbucket.com
HostName bitbucket.com
user git
IdentityFile ~/.ssh/tisgoed@bitbucket.com.ed25519
IdentitiesOnly yes
...
The SSH-Host identifies the account to be used to login to the git-provider.
For each git account you will need to add a different section in your ~/.ssh/config
file.
Step 3: Set the remote origin
When you clone a new repository you end up with the default remote origin in your .git/config
configuration.
A partial example of the default `[remote “origin”] in your fresh git-configuration:
...
[remote "origin"]
url = git@github.com:tisgoed/my-new-repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
...
As you can see the url
points to your repository but the way it wants to connect does not use the named configuration.
We need to modify the default remote origin to use our named SSH configuration.
See the syntax and the example below on how to modify the remote origin through the command line.
The syntax:
git clone git@github.com:[git-user.name]/[repo-name].git
cd [repo-name]
git remote add origin git@[git-user.name]-[git-provider]:[git-user.name]/[repo-name].git
An example:
git clone git@github.com:tisgoed/silly-repo-name.git
cd silly-repo-name
git remote add origin git@tisgoed-github.com:tisgoed/silly-repo-name.git
The url
in the [remote "origin"]
of the git-configuration should be changed similar to the example below:
...
[remote "origin"]
url = git@tisgoed-github.com:tisgoed/silly-repo-name.git
fetch = +refs/heads/*:refs/remotes/origin/*
...
Altough this is a good solution, and it gives you full flexibility on the working directory, the alternative option simplifies it even further without touching the ~/.ssh/config
file and setting the specific remote origin for each repository.
New repo workflow (method 1)
When you need to create a new repo at an existing git-provider, the following steps apply:
- Browse to your (git-provider)
- Login to your account (git-user.name)
- Create a new repository (repo-name
git clone git@[git-provider]:[git-user.name]/[repo-name].git
cd [repo-name]
git remote add origin git@[git-user.name]-[git-provider]:[git-user.name]/[repo-name].git
touch README.md
git add .
git commit -m "Initial commit"
git push -u origin master
Step 4 and 6 could be combined in this workflow. I have tried this workflow for a while and noticed that I needed all ten steps simply because I could not remember the named of the SSH-section.
git clone git@tisgoed-github.com:tisgoed/silly-repo-name.git
Method 2: Use the git includeIf
directive
The includeIf-method uses the git directive includeIf
that enables you to include files when a certain condition is true.
If you use git within a certain path, the content of a specific file is added to the active git-configuration. The included file contains information to access a specific git-provider.
This method requires more steps to set up but there is no need to remember a named SSH-section.
Diagram with the includeIf
flow
The following diagram describes the configuration for a new git account:
The basic steps to set it up for a new git-provider:
- Create SSH-keys
- Set up a directory structure
- Create the include file(s)
- Add the “includeIf” to the git configuration
- Verify the loading of the conditional git config (optional)
The baseline for setting the SSH-keys is already described in the second paragraph. Moving on to step 2.
Step 2: Git directory structure
Different directory structures are possible. I tried various structures like:
- “~/git/[git-provider]/[git-user.name]” and
- “~/[git-provider]/[git-user.name]”
- “~/git/[git-user.name]@[git-provider]/”
My current preferred directory structure is “~/git/[git-user.name]@[git-provider]/”.
An example of my git “root” directories:
...
git
├── tisgoed@bitbucket.com
├── tisgoed@gitlab.com
└── tisgoed@github.com
...
The further description of the includeIf-method is based on this directory structure.
Step 3: The git-include file(s)
In my user-root (~) directory next to the .gitignore
and the .gitconfig
I created a directory named .gitinclude
to store the include files.
...
.gitconfig
.gitignore
.gitinclude
├── tisgoed@bitbucket.com.include
├── tisgoed@gitlab.com.include
└── tisgoed@github.com.include
...
The following naming convention is used for the include files:
[git-user.name]@[git-provider].include
The content of an include file requires at least the following two sections:
user
-section, user dataname
, the user name at the git-provider.email
, the email address at the git-provider.
core
-section,sshCommand
, the reference to the provider specific SSH-key
An include template:
[user]
name = [git-user.name]
email = [git-user.email]
[core]
sshCommand = "ssh -i ~/.ssh/[user-name]@[git-provider].ed25519"
An include example, ~/.gitinclude/tisgoed@github.com.include
[user]
name = tisgoed
email = a.w.alberts@tisgoed.nl
[core]
sshCommand = "ssh -i ~/.ssh/tisgoed@github.com.ed25519"
Step 4: The ~/.gitconfig
file
Once an include file is created we can add the includeIf
section to the ~/.gitconfig
file.
At first the syntax for the includeIf
directive is a bit confusing. Basically it comes down to the following pseudocode:
if (git-repository is placed within path) then
add configuration from file
end if
The template for the includeIf
section in the ~/.gitconfig
file:
...
# Git includes
# git-user.name @ git-provider
[includeIf "gitdir/i:~/git/[git-user.name]@[git-provider]/"]
path = ~/.gitinclude/[git-user.name]@[git.provider].include
...
An example with three different git accounts in the ~/.gitconfig
file.
...
# Git includes
# tisgoed @ bitbucket.com
[includeIf "gitdir/i:~/git/tisgoed@bitbucket.com/"]
path = ~/.gitinclude/tisgoed@bitbucket.com.include
# tisgoed @ github.com
[includeIf "gitdir/i:~/git/tisgoed@github.com/"]
path = ~/.gitinclude/tisgoed@github.com.include
# tisgoed @ gitlab.com
[includeIf "gitdir/i:~/git/tisgoed@gitlab.com/"]
path = ~/.gitinclude/tisgoed@gitlab.com.include
...
Step 5: Verify the git configuration
While setting things up you can use the git config --list
command to check if the include file was loaded into the git configuration. It should display the user.name and the user.email from the include file.
⚠️ The following command only works in a ‘git’ directory.
The command:
git config --list | grep "user."
A sample of the expected output
user.name=tisgoed
user.email=a.w.alberts@tisgoed.nl
New repo workflow (method 2)
When you need to create a new repo at an existing git-provider, the following steps apply:
- Browse to your (git-provider)
- Login to your account (git-user.name)
- Create a new repository (repo-name)
cd ~/git/[git-provider]
git clone git@[git-provider]:[git-user.name]/[repo-name].git
cd [repo-name]
touch README.md
git add .
git commit -m "Initial commit"
git push -u origin master
Conclusion
Pro’s and con’s of both solutions:
- Use named SSH configurations in the
~/.ssh/config
file.- Full flexibility on the location of your repositories.
- Requires setting git-account per git-provider in
~/.ssh/config
. - Requires setting the remote origin SSH-setting in the repository.
- Requires you to remember the name of the SSH-section.
- Using the git
includeIf
directive.- Static “root”-directory per git-account.
- Create
git-include
file per git-account. - Requires changing your
~/.gitconfig
file per git-account.
I tried both methods and personally I prefer the second option. It forces you to keep a clear separation between the different git-accounts, there is no need to change the default remote origin and there is no need to remember the name of the SSH-section.
References
- How to Deal with Multiple GitHub Accounts on One Computer
- Setting up multiple GitHub accounts, the nicer way
Git conditional includes:
Git tooling:
- Create new github repo from command line
- GitHub/hub, A command-line tool that makes git easier to use with GitHub.
- hub: use github from the command-line
ED25519:
-
ED25519 is an elliptic curve cryptography(ECC) signature algorithm. The Ed25519 signature alghorithm offers high security signatures with a small signature size. ↩︎