Disclaimer: ok, Git "accounts" don't exist - we only have Git configurations. The title is an unorthodox shortcut to talk about accounts hosted by GitHub, Gitlab, Bitbucket and such. Not using these? Don't worry, you can still make great use of this cheat sheet to level up your .gitconfig game (look at step n°7).

Introduction

Let’s imagine a scenario: you’ve just joined a new company, it’s your first day and you need to set up your new machine. The first thing you do is to rush to get your own GitHub SSH key and install it so you can still work on your hobby project.
A bit later that day, you are finally able to login to your organization repository and you now need to install this key as well to be able to start working.

This is where you realize it’s essential to know how to manage multiple Git accounts on the same machine safely.

Want to set up this straight once and for all? We have you covered!
Take a look at the cheat sheet below! (you can also bookmark or share it)

Download the Git accounts cheatsheet

One key insight from our State of Secrets Sprawl 2021 is that 85% of all the secrets we catch by live monitoring GitHub are exposed through developers’ personal repositories, and a large share of them are in fact corporate secrets.

Multiple hypotheses can explain why this happens. Of course, we cannot discard malicious behaviors, which include corporate resources hijacking and other shady motives. But the sheer scale of the phenomena hints at something else: we are convinced that most of this happens because error is human and misconfiguring Git is easy. You think that you are git push ing your work with your pro account (by the way, secrets should never enter any repo), while you're actually using your personal one...

Furthermore, any Git repo has a memory that is not easy to rewrite (that’s a feature!). If you want an awesome cheat sheet for rewriting the Git history, check it out!

First things first: SSH or HTTPS?

Most VCS support authentication with SSH or HTTPS: to make things easier, always prefer using SSH where possible.
Git does not cache the user's credentials by default, so with HTTPS, you need to re-enter them each time you perform a clone, push, or pull.
On the other hand, SSH is safer and, when set up correctly (which will be once you follow this guide), you can completely forget about it!

A quick reminder on how it works

When you hear about an SSH key, most of the time it’s a shortcut to refer to an SSH key pair, composed of a public and a private key, which are cryptographically linked.

The public key, as the name suggests, is openly distributed and shared with all parties. It is used to encrypt messages that can only be decrypted by its private counterpart.

For the connection to be secured, it is essential that the private key remains secret.

The strength of the entire connection lies in the fact that the private key is never revealed, as it is the only component capable of decrypting messages that were encrypted using its own public key.

Note that the SSH protocol uses a mix of asymmetric and symmetric encryption as well as hashing, and the former is not used to encrypt the entire SSH session. Instead, it is only used as a final step to authenticate the client before starting a session. You can learn more about the protocol here.

Step-by-step

Now that you understand the basics of SSH, there is one simple rule to follow:

one SSH keypair = one Git account

The problem is now to manage safely multiple SSH keys and make sure you always use the appropriate one.
Let’s start from the beginning, generating a new key pair for your personal account:

1. Generate an SSH key

ssh-keygen -t ed25519 -C "your_personal_email@example.com" -f ~/.ssh/<personal_key> 

ED25519 are recommended for security and performance, but RSA with a sufficient length is also a valid alternative:

ssh-keygen -t rsa -b 4096 -C "your_personal_email@example.com" -f ~/.ssh/<personal_key> 

-C is for adding a comment, it can be anything but it will be helpful to know the email associated with your account
-f is to define a filename, and creating a key with a descriptive name will help you remember which key is used for which user/remote

2. Add a passphrase

Next, you will be prompted to add an (optional) passphrase. We recommend you do so because it adds an extra layer of security: if someone gains access to your computer, your keys will be compromised unless they are attached to a passphrase.

To update the passphrase for your SSH keys:

ssh-keygen -p -f ~/.ssh/<personnal_key>

You can check your newly created key with:

ls -la ~/.ssh

which should output <personal_key> and <personal_key>.pub.
By default, ssh searches for filenames of public keys looking like id_<algorithm>.pub, but in our case this is not a problem since we are going to specify what keys to use next.

3. Tell ssh-agent

We will use ssh-agent to securely save your passphrase. Make sure the ssh-agent is running and add your key (the -K option is to store the passphrase in your keychain, macOS only).

eval "$(ssh-agent -s)" && \
ssh-add -K ~/.ssh/<personal_key> 

4. Edit your SSH config

If you don’t have one, create an SSH config file
touch ~/.ssh/config and add the following contents to it:

Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/<created_key>

Here we are setting Host to * for every key because we will use Git configs to select the appropriate SSH key based on profiles, which will give us a bit more flexibility (more on that later).

5. Copy the SSH public key

(<personal_key>.pub) to your VCS of choice (GitHub, GitLab or BitBucket etc...)

macOS

tr -d '\n' < ~/.ssh/<created_key>.pub | pbcopy

Linux

xclip -sel clip < ~/.ssh/<created_key>.pub

Windows

cat ~/.ssh/<created_key>.pub | clip

6. Structure your workspace for different profiles

Now, for each key pair (aka profile or account), we will create a .conf file to make sure that your individual repositories have the user settings overridden accordingly.
Let’s suppose your home directory is like that:

/myhome/
    |__.gitconfig
    |__work/
    |__personal/

We are going to create two overriding .gitconfigs for each dir like this:

/myhome/
|__.gitconfig
|__work/
     |_.gitconfig-work
|__personal/
    |_.gitconfig-pers

7. Set up your Git configs

# ~/personal/.gitconfig.pers
 
[user]
email = your_pers_email@example.com
name = Your Name
 
[github]
user = “mynickname”
 
[core]
sshCommand = “ssh -i ~/.ssh/<personal_key>”
# ~/work/.gitconfig.work
 
[user]
email = your_pro_email@google.com
name = Your Name
 
[github]
user = “pro_name”
 
[core]
sshCommand = “ssh -i ~/.ssh/<professional_key>”

Here we tell Git which key to use by making explicit the SSH command (the -i option is for specifying an identity file or key). This gives us more control, for instance, imagine you have multiple accounts on the same host (like github.com), if you were using the SSH config file to use different SSH keys, you would need to create and remember an arbitrary prefix like first.github.com and then remember to use that domain each time you want to clone a repository with this account. In our opinion, it is less flexible and a bit cumbersome.

This is what you global .gitconfig can look like:

# ~/.gitconfig
 
[includeIf “gitdir:~/personal/”] # include for all .git projects under personnal/ 
path = ~/personal/.gitconfig-pers
 
[includeIf “gitdir:~/work/”]
path = ~/work/.gitconfig-work
 
[core]
excludesfile = ~/.gitignore      # valid everywhere

Of course, because many settings will probably be common to the two configurations (like your name or your editor preferences), you can set them here.

As a reminder, Git uses 3 overriding levels for configuration: system, global and local (project). More information here on config options.

To see a list of all config the options

man git-config

To check your activated config options

git config -list

8. Repeat for every account/profile

You can repeat these steps for all your VCS accounts and forget about it from now on!

You're done!

you can now choose to, clone your repo, add or change your remote with:

git clone git@<repository.domain.com>:<username>/<repo_name>.git
git remote add origin git@<repository.domain.com>:<username>/<repo_name>.git
git remote set-url origin git@<repository.domain.com>:<username>/<repo_name>.git

Pro Tip: use the includeIf statement to setup platform-specific configs

[includeIf "gitdir:/Users"]
    path = ~/.gitconfig-macos
[includeIf "gitdir:C:"]
    path = ~/.gitconfig-windows
[includeIf "gitdir:/home"]
    path = ~/.gitconfig-linux

For more cheat sheets, subscribe to the blog below to receive them directly in your mailbox!