Skip to content

Git and SSH

When using Git with Secure Shell (SSH) to connect from a Git client to a Git server, these are the tricks to handle multiple Github/Gitlab accounts to connect to multiple Github/Gitlab servers.

This spawns out of a necessity to manage a chaotic environment with

  1. numerous Git (ex. Github, Gitlab, Bitbucket) accounts,
  2. many SSH keys associated with different identities,
  3. and many different Git servers to connect to.

This guide assumes you're in a Unix/Linux environment or a Linux like environment such as cygwin.

Overview

  1. Separate folders when cloning a different Git account user's repository to ensure we don't mix and match two different user handles when working on a repository.
  2. Separate .gitconfig files to separate Git identity - name and email separation for selective folders.
  3. Separate SSH keys for identity management when identifying as a Git user to connect to a Git server.
  4. Separate SSH Configuration as a configuration to connect to different Git servers using different Git users.
  5. (Optional) Automate cloning and pulls so that we have a history of what's in the folders.

Organize Folder Structure

I favor creating a single code folder for all code related artifacts. Within the folder, I create subfolders aligned to Git servers and Git profiles I intend to associate with. For example, image user1 is the name of the user.

We can have multiple folder representing different organizations and projects underneath. Each organization tends to associate with a Git server (ex. Github, Gitlab, etc) or an organization within Github or Gitlab (ex. https://github.com/google). Each project underneath is a Git repository.

Once we organize our folder structure in this manner, we can setup Git identity to associate our Git identity (username, email) to each of the organization folders.

/home/user1/code
├── org1
 ├── project1
 ├── project2
├── org2
 ├── project1
 ├── project2
├── org3
 ├── projectz
├── org4
 ├── project9
 ├── projectb

Git Config Identity

Most people set their Git identity manually using the command line once globally because Git commits requires it. Git server providers such as GitHub also verifies Git commit via Git config email to put a Verified badge on the commit.

The most common way done manually is via the command line:

# To set your name and email address globally, use the following commands in your terminal:
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

Note

GitHub recommends using a noreply email they provide to avoid getting spammed by soliciters seeking to profit off your Git commit emails.

To automate git config across the folder structure setup previously, we create a gitconfig file that is stored the root of our directory. This file has no file extension and is a simple text file.

For example, my .gitconfig file is located at ~/.gitconfig or /home/user1/.gitconfig.

Next, we include an includeIf clause to point at each of the folder structure created earlier, the path after gitdir: must end in / to represent a directory. This instructs Git that when looking in the path of ~/code/org/, to use the configuration specified in the path, .gitconfig-org1.

[includeIf "gitdir:~/code/org1/"]
  path = .gitconfig-org1
[includeIf "gitdir:~/code/org2/"]
  path = .gitconfig-org2
[includeIf "gitdir:~/code/github-org1/"]
  path = .gitconfig-github-org1
[includeIf "gitdir:~/code/github-org2/"]
  path = .gitconfig-github-org2
[includeIf "gitdir:~/code/gitlab-org1/"]
  path = .gitconfig-org1
[core]
  attributesfile = .gitattributes

The .gitconfig-org1 file includes a configuration of the user's name and email address.

Note

If you decide to keep your email private for Github, go to Github email settings and navigate to the section of the Github provided email you should use.

[user]
name = "user1"
email = 1234556+user1@users.noreply.github.com

SSH Keys

SSH Keys serves as another way other than passwords for a SSH client to authenticate to a SSH server. Typing in passwords to login every time is rather annoying. The security tradeoffs are often debated between using passwords and using SSH keys for authentication.

To generate SSH keypairs of public and private key as a client, I prefer ED25519 based keys, as they're faster and smaller than RSA based keys.

ssh-keygen -t ed25519 -o -a 100 -C "email@example.com" -f ~/.ssh/example_network_id_ed25519

Otherwise, to generate a RSA 4096 bits keypair:

Note

RSA 2048 bit keys are still widely in use until standards phases it out in 2030. It is about 4x faster than RSA 4096 bit keys to use while RSA 4096 bit keys have slightly better encryption strength.

ssh-keygen -t rsa -b 4096 -C "email@example.com" -f ~/.ssh/example_network_id_rsa

(Optional) You may choose to add a passphrase for extra security and to avoid having to type the password again, it's best to have it cached once with an SSH agent.

To run SSH agent, run the following:

eval "$(ssh-agent -s)"

(Optional) Add your SSH key to the SSH agent.

ssh-add ~/.ssh/example_network_id_ed25519

The SSH convention for keys is that the private key file has no extensions while the public key file has a .pub extension.

SSH Configurations

SSH Configurations determines what SSH keypair and identity to use when a Git client tries to connect to a Git server; it binds the usage of the keypair with the SSH client's identity when connecting to a Git server listening for SSH connections.

The SSH configuration is a single file config in the directory path ~/.ssh/config.

I modify the config file to target a specific HostName (ex. github.com, gitlab.com) to use a particular User (ex. git) and prefer to use the authentication method of publickey instead of password and select the SSH private key path as the IdentityFile. The config file can include numerous SSH configurations for the different Hosts (ex. Github, Gitlab, Bitbucket) to target.

Host github.com-org1
  HostName github.com
  User git
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/git/github_org1_ed25519
  IdentitiesOnly yes

Host github.com-org2
  HostName github.com
  User git
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/git/github_org2_ed25519
  IdentitiesOnly yes

Host gitlab.com-org1
  HostName gitlab.com
  User git
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/git/gitlab_org1_ed25519
  IdentitiesOnly yes

Automate Cloning and Pulls

clone.sh to clone a number of repositories into a folder.

Note

Notice below that git@github.com-org1 matches our HostName field in the SSH configuration so that the Git client can associate a Git user with a Git server. The SSH configuration binds the Git association together, to select a particular Git user with a particular SSH key for a particular Git server target.

#!/usr/bin/env bash
git clone git@github.com-org1:fartbagxp/aas-cidr-ranges.git
git clone git@github.com-org1:fartbagxp/git-and-ssh.git
git clone git@github.com-org1:fartbagxp/asdf-oauth2c.git

Following the folder structure we setup, we may have another clone.sh script for another organization and the configuration binds the Git user, the unique SSH key, and the Git server target together.

#!/usr/bin/env bash
git clone git@gitlab.com-org1:dwt1/dotfiles.git
git clone git@gitlab.com-org1:wireshark/wireshark.git

(Optional) To sync repositories without verifying, pull.sh updates all repositories in a folder. This will cause git conflicts if there are unmerged changes!

#!/usr/bin/env bash

for d in */ ; do
  echo $d
  git -C $d pull
done

Miscellaneous Tricks

There are often tricky scenarios when trying to clone or push a project to a Git server based on how our clients connect to the server (sometimes crossing intermediate firewalls) for the first time.

These are some debugging tips whether using SSH or HTTPS to connect to the Git server.

Debugging SSH on Git

When using Git as a client to connect to a server via the SSH protocol, the default git clone <repository> does not offer any helpful debugging messages when a failure happens because of the SSH connection.

To enable debugging messages, we can prepend the environment variable GIT_SSH_COMMAND before running git clone.

GIT_SSH_COMMAND=“ssh -v” git clone git@github.com:github/training-kit.git

For more verbose output -

GIT_SSH_COMMAND=“ssh -vvv” git clone git@github.com:github/training-kit.git

Debugging HTTPS on Git

If the Git server or some intermediate firewall blocks SSH connections to the Git server, we have to rely on the HTTPS protocol to connect to it.

Use nc and curl as tools first to determine connectivity.

To test whether you can establish a TCP-based connection to the Git server on the standard SSH port 22:

nc -vz -w 3 github.com 22

If the output shows that the connection failed and your regular internet is working, it is likely an intermediate firewall somewhere is blocking your connection or that the Git server doesn’t want to establish a connection over SSH with you.

Alternately, run a curl connection to test https

curl -vv https://github.com

A wall of text should appear to fetch the website, showing success. Otherwise, if the connection fails or hangs, it shows a failure, and there’s nothing more we can do.

If it is successful, we can then use git to clone a repository over https.

git clone https://username@github.com/username/repository.git

Alternatively, if you prefer using your password directly in a less secure fashion - where we expose the password in the command line storing history

git clone https://username:password@github.com/username/repository.git

A third way to clone is to use a Personal Access Token common among many Git based servers.

git clone https://*token*@github.com/username/repository.git

SOCKS Proxy with Git

A SOCKS Proxy is useful to get around firewall or network blockage of a HTTPS connection to the Git server.

Once we established a SOCKS Proxy, we can run the following to run git clone command, proxying the HTTPS connection to a SOCKS proxy.

This example uses the 127.0.0.1 (localhost) as the connection point of the SOCKS proxy and 8055 as the port of the proxy.

ALL_PROXY=socks5h://127.0.0.1:8055 git clone https://username@github.com/username/repository.git