setup multiple git accounts on one local machine
Tags: tutorial, git, gitlab, github
Published: 2022-12-01 18:05:59

Developers now-a-days have multiple Git Service Provider Accounts. I use GitLab for my personal projects & GitHub for professional repos. This tutorial applies to people who would like to setup multiple GitLab/GitHub/BitBucket on their machine.


My local machine specifics at the time of writing this:

```console
$ git --version
git version 2.38.1
```

```console
$ sw_vers
ProductName:		macOS
ProductVersion:		13.0
BuildVersion:		22A380
```
---
## <u>1. generate SSH key</u>

```console
$ ssh-keygen -t ed25519 -C "your_personal_email@example.com" -f ~/.ssh/<ssh_key_name>
```
* `ssh-keygen` generates the authentication keys for SSH. 
* `-t` flag specifies the type of key to be generated. In this case the type is `ed25519`. ED25519 is the recommended cryptographic public-key signature system. 
* `-C` flag is for adding a comment. In this case it will be your email. You may replace `your_personal_email@example.com` with your git service provider email. 
* `-f` flag specifies the file name of the key that will be generated. You may replace `<ssh_key_name>` with your own key name. I named it `GitLab_key`.

## 2. <u>add passphrase to SSH key</u>
Running the above command will prompt for adding a passphrase. Even though the process makes this step optional, it is highly recommended from security standpoint. Keys with pass phrase may not get compromised even if someone gains access to your machine.

```console
$ ls -la ~/.ssh/
total 112
<snip>
-rw-------   1 user  staff   484 Feb 29 13:26 GitLab_key
-rw-r--r--   1 user  staff   113 Feb 29 13:26 GitLab_key.pub
<snip>
```
Public - Private key pair will be generated in the `.ssh` folder.

## 3. <u>add SSH key to `ssh-agent`</u>

```console
$ eval "$(ssh-agent -s)" && \
ssh-add -K ~/.ssh/<ssh_key_name>
```
* `eval` executes the argument as shell command. The argument here is `$(ssh-agent -s)`
* `&& \` allows you to enter another command in the next line before evaluating the argument and executing the command.
* The next line will output `cmdand>` where you will have to enter `ssh-add -K ~/.ssh/<ssh_key_name>`.
* `ssh-add` will add the mentioned identity file to the authentication agent. 
* `-K` is a deprecated version of Mac OS's 12 and newer `--apple-use-keychain` flag. For now either one works. Both these flags stores the passphrase in your keychain when you add an SSH key to the ssh-agent.

> _Just like before you may replace `<ssh_key_name>` with your own key name._

## 4. <u>setup SSH `config` file</u>
Check if file named as `config` is present in the `.ssh` directory.
```console
$ touch ~/.ssh/config
``` 
**If config file is not present in the `.ssh` folder then create one.** `touch` will create `config` file in the `~/.ssh/` directory path.

There are multiple ways to add the lines of text in this file, however I will provide with two of the easiest ways:
###4.1. add text from text editor
I use `sublime text` as my go to text editor.
```console
$ subl ~/.ssh/config
```
* `subl` followed by the path name `~/.ssh/config` will open the `config` file in the sublime text editor.
``` 
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/<ssh_key_name>
```
Add the above lines of text as it is to the file and save it.
> _Just like before you may replace `<ssh_key_name>` with your own key name._

###4.2. add text from the terminal
In case you don't know how to open `config` file in text editor, you can get this on the terminal itself.
```console
$ echo "Host *" > ~/.ssh/config
$ echo "  AddKeysToAgent yes" >> ~/.ssh/config
$ echo "  UseKeychain yes" >> ~/.ssh/config
$ echo "  IdentityFile ~/.ssh/<ssh_key_name>" >> ~/.ssh/config
```
* `echo` will pass the string to the file mentioned in the path `~/.ssh/config`
* `>` will overwrite the whole contents of the mentioned file with the passed string mentioned inside the double quotes.
* `>>` will append the string to the mentioned file at the end.

## 5. <u>copy SSH public key</u>
You need to copy the contents of the generated public key to add the SSH key to the Git Service Provider account.
```console
$ pbcopy < ~/.ssh/<ssh_key_name>
```
* `pbcopy` is equivalent to `ctrl+c` in mac terminal. It will copy the contents of the file mentioned the path `~/.ssh/<ssh_key_name>`

## 6. <u>create workspace</u>
Global `.gitconfig` is present in the home directory of your machine. `~` pronounced as _til·​de_ is shorthand for contents of the environment variable `HOME` or by default the home directory in Unix (including Mac) machines.
Below is the Folder Structure I am using as my workspace to neatly divide the multiple git service provider repos.
```
/~/
    |__.gitconfig
    |__/git_repos/
        |__GitHub/
            |__.gitconfig.GitHub
        |__GitLab/
            |__.gitconfig.GitLab
```
You can structure your workspace in any way but remember the path for the additional `.gitconfig.<name>`. These git configs are going to override the global git config.

## 7. <u>setup git config</u>
Out of the two options, adding config via a text editor vs git config command entry; I choose the latter. That is because adding config via text editor has always been a hit or miss for me. This problem was one of the motivations as well for me in writing this post.
```console
$ git config -f .gitconfig.<name> --add user.email <your_gitlab_email@example.com>
$ git config -f .gitconfig.<name> --add user.name <your_user_name>
$ git config -f .gitconfig.<name> --add gitlab.user <your_gitlab_user_name>
$ git config -f .gitconfig.<name> --add core.sshCommand "ssh -i ~/.ssh/<ssh_key_name>"
```
* `git config` will set the specified git configuration to the file.
* `-f` option lets you choose specified `.gitconfig.<name>` file in which the configuration will be stored.
* `--all` option adds a new line to the configuration file without altering the previously written values.
* Values from `user.name` & `user.email` variables ends up in the author and committer field of commits.
* Value in `gitlab.user` variable should be your GitLab Username. 
* Value in `sshCommand` specifies the exact Identity file (using `-i` flag for `ssh`) that needs to be used for a particular repo.
```
# ~/git_repos/GitLab/.gitconfig.GitLab

[user]
	email = <your_gitlab_email@example.com>
	name = <your_user_name>
[gitlab]
	user = <your_gitlab_name>
[core]
	sshCommand = ssh -i ~/.ssh/<ssh_key_name>
```
* After running all the `git config` commands your `.gitconfig.<name>` file should look like the above snippet.

> _You may replace all the value with your own that are within `<``>`._

Now you need to specify the additional `.gitconfig.<name>` file in the Global `.gitconfig`.
```console
$ git config -f .gitconfig.<name> --add includeIf."gitdir:~/git_repos/GitLab/".path ~/git_repos/GitLab/.gitconfig.GitLab
```
`includeIf.<condition>.path` variable can include additional git config file is the condition is True. Here the condition is if git directory - `gitdir:` is `~/git_repos/GitLab/` and if it's True then the git config file specified in the `path` will be used.
```
<snip>
[includeIf "gitdir:~/git_repos/GitLab/"]
	path = /Users/mac_user/git_repos/GitLab/.gitconfig.GitLab
<snip>
```
I have snipped the output of what Global `.gitconfig` could look like to avoid confusion as your `.gitconfig` may have some more config (which is fine).

## 8. <u>repeat the steps to setup another account</u>
You can repeat these step for additional account from the same/different service provider.
```console
$ git config -l
```
This command will list all the variable and their values in the .gitconfig file.

---
In case you are facing issues in adding another account while/after repeating the above steps then head over to [2nd iteration post](https://dev.to/kakarr0tt0/setup-multiple-git-accounts-on-one-local-machine-2nd-iteration-5e2e) to understand what is the expected outcome.

I would like to mention this post by **_Thomas Segura_** - [8 Easy Steps to Set Up Multiple GitHub Accounts](https://blog.gitguardian.com/8-easy-steps-to-set-up-multiple-git-accounts/) which initially helped me in understanding how it needs to be done. I ran into couple of problems that resulted in writing this post with tweaks to some of the steps mentioned in Thomas's Post. I am not a technical writer but he is; so if you can header over to his post and please show the guy some love.