Disclaimer: although the title mentions GitHub, this cheat sheet is also applicable for the other major VCS platforms such as Gitlab and Bitbucket. 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).

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 configs on the same machine safely.

Git Config Made Easy

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 GitHub accounts cheatsheet

One key insight from our State of Secrets Sprawl 2022 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 history 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 config

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. Git config example

# ~/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 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

Before you go

Do you want to accelerate your learning journey in the world of code security? Dive into our 📚 collection of cheat sheets to level up your skills! Check it out here: Cheat Sheet Collection

Secrets at the Command Line [cheat sheet included]
Developers need to prevent credentials from being exposed while working on the command line. Learn how you might be at risk and what tools and methods to help you work more safely.
API Keys & Secrets Management Best Practices - GitGuardian Blog
We have compiled a list of some of the best practices to prevent API key leakage and keep secrets and credentials safe. Secrets management doesn’t have a one-size-fits-all approach, so this list considers multiple perspectives so you can be informed in deciding to or not to implement strategies.
Secure Code Review Best Practices [cheat sheet included]
Reducing vulnerabilities in your software means manual and automated secure code reviews. Download our handy cheat sheet to keep your review practice on track.
GitHub Actions Security Best Practices [cheat sheet included]
Learn how to secure your GitHub Actions with these best practices! From controlling credentials to using specific action version tags, this cheat sheet will help you protect against supply-chain attacks. Don’t let a malicious actor inject code into your repository - read now!