Notes on Git Setup with SSH for Windows (GitHub)

There are many guides on how to install and configure Git on a Windows PC. As I test new developer laptops for Wehkamp, it makes sense to have some notes on how to do it. Most Windows developers use git HTTPS cloning, but this guide shows how to install and configure SSH. All scripts should run in PowerShell.

Step 1: Git install

There are many ways to install git, I use Chocolatey:

choco install git.install

Step 2: Configure Git

Before we start, let's make sure our git settings are set:

& {
  $gitUsername = Read-Host "Enter Git username"
  $gitEmail    = Read-Host "Enter Git email"

  git config --global user.name  "$gitUsername"
  git config --global user.email "$gitEmail"

  # "Fix" line endings, so your Linux (Docker) and Windows (host) think alike:
  git config --global core.eol lf
  git config --global core.autocrlf false

  # Convenience, make it easier to push newly created branches
  git config --global push.autoSetupRemote true
}

Step 3: Install OpenSSH

Next, we'll need to install OpenSSH in Windows. With the installed tools we can generate a new SSH key and add it to our GitHub account.

Run the following from an elevated PowerShell (Windows Key + X, A):

& {
  # Install the OpenSSH Client
  Add-WindowsCapability -Online -Name OpenSSH.Client

  # Start the sshd service
  Start-Service sshd

  # OPTIONAL but recommended:
  Set-Service -Name sshd -StartupType 'Automatic'

  # Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify
  if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
    Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
    New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
  } else {
    Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
  }

  # Start SSH agent
  Set-Service -Name ssh-agent -StartupType Automatic
  Start-Service ssh-agent
}

Step 4: Generate a New SSH Key

Let's continue in a normal (unelevated) PowerShell. The following command will generate new SSH key for the email you've registered in the previous step:

$email = git config --global user.email
ssh-keygen -t ed25519 -C $email

You will be prompted for a passphrase. When you enter one, note that you will need to enter it every time you push or pull from Git. This will make it more secure (as only you know the passphrase), but it might make pushing and pulling a bit cumbersome.

Add the key to the SSH agent:

ssh-add

Copy the public key to your clipboard:

& {
  Get-Content ~/.ssh/id_ed25519.pub | Set-Clipboard; `
  echo "Key copied to clipboard.";
}

This will copy something like ssh-ed25519 IAMASUPERLONGANDSECUREKEY my@email.com to your clipboard.

Step 5: Add SSH Key to GitHub

Add the new SSH key to your GitHub account:

  1. Open your keys in your profile on GitHub: https://github.com/settings/profile
  2. Click the New SSH Key button.
  3. Enter a Title for the authentication key and paste the clipboard into the Key field.
  4. Click Add SSH Key.

Step 6: Test SSH Connection

Verify that the SSH setup is working by running:

ssh -T git@github.com

It should show something like: Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access.

🥳 That's it! You’re now set up to use Git with SSH on Windows. Consider adding a GPG key to sign your commits for additional security.

Bonus: convert cloned repo from HTTPS to SSH

So, what if you have a previously cloned your repo with HTTPS and you want to change it to SSH? You can use the following PowerShell script to change the settings:

$remoteOriginUrl = git config --get remote.origin.url; `
Write-Host "Remote url: $remoteOriginUrl" `

if(!$remoteOriginUrl.StartsWith("https://")) {
    Write-Host "Remote origin does not start with https://, so it can't be converted.";
    exit 0;
} else {

    # replace https
    $remoteOriginUrl = $remoteOriginUrl.Replace("https://", "git@");
    # postfix with .git
    $remoteOriginUrl += ".git"
    $remoteOriginUrl = $remoteOriginUrl.Replace("/.git", ".git");
    $remoteOriginUrl = $remoteOriginUrl.Replace(".git.git", ".git");
    # replace first slash after extension
    [regex]$pattern = "(\.[^/]+)/";
    $remoteOriginUrl = $pattern.replace($remoteOriginUrl, '$1:', 1) ;

    git remote set-url origin $remoteOriginUrl

    Write-Host "Remote url is now: $remoteOriginUrl"
}

Additional Resources

While researching how to set this up, I've use the following sources:

expand_less brightness_auto