Making Git SSH Commands Permanent: Best Practices for Repository-Specific SSH Keys

Share
Making Git SSH Commands Permanent: Best Practices for Repository-Specific SSH Keys
Streamline your multi-key workflow for Git

The Problem

Have you ever found yourself typing this long command every time you want to pull from a specific repository?

GIT_SSH_COMMAND='ssh -o IdentitiesOnly=yes -i /root/.ssh/repo' git pull

It's tedious, error-prone, and breaks your workflow. Let's fix that permanently.

Quick Solution: Repository-Specific Git Config

The cleanest solution is to use Git's built-in core.sshCommand setting at the repository level:

git config --local core.sshCommand "ssh -o IdentitiesOnly=yes -i /root/.ssh/repo"

After this one-time setup, you can simply run:

git pull
git push
git fetch
# All Git operations will use your custom SSH command

Alternative Approaches

Option 1: Global Git Config (For All Repositories)

git config --global core.sshCommand "ssh -o IdentitiesOnly=yes -i /root/.ssh/repo"

⚠️ Caution: This applies to every Git operation on your system.

Option 2: Shell Alias

Add to ~/.bashrc, ~/.zshrc, or ~/.bash_aliases:

alias gmirror='GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i /root/.ssh/repo" git'

Usage: gmirror pull

Option 3: Environment Management with direnv

Create .envrc in your repository:

export GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i /root/.ssh/repo"

Then run direnv allow. The variable activates when you enter the directory.

Option 4: SSH Config File (Most Elegant for Multiple Keys)

Edit ~/.ssh/config:

# Specific host with custom key
Host github-repo
    HostName github.com
    User git
    IdentityFile /root/.ssh/repo
    IdentitiesOnly yes

# Or match by repository pattern
Match host github.com exec "[[ $PWD =~ /path/to/your/repo ]]"
    IdentityFile /root/.ssh/repo
    IdentitiesOnly yes

Then change your remote URL:

git remote set-url origin git@github-repo:username/repo.git

Best Practices for Managing Multiple SSH Keys

1. Use SSH Config for Complex Setups

The SSH config file is the most maintainable solution when juggling multiple keys:

# Personal GitHub
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_personal
    IdentitiesOnly yes

# Work GitHub
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_work
    IdentitiesOnly yes

# GitLab (different host)
Host gitlab.com
    HostName gitlab.com
    User git
    IdentityFile ~/.ssh/id_rsa_gitlab
    IdentitiesOnly yes

# Legacy server with non-standard port
Host old-git-server
    HostName git.legacy.com
    Port 2222
    User git
    IdentityFile ~/.ssh/id_rsa_legacy

2. Directory-Based SSH Config with Match

Use the Match directive for automatic key selection:

# Auto-select key based on current directory
Match host github.com exec "[[ $PWD =~ /work/ ]]"
    IdentityFile ~/.ssh/id_rsa_work
    IdentitiesOnly yes

Match host github.com exec "[[ $PWD =~ /personal/ ]]"
    IdentityFile ~/.ssh/id_rsa_personal
    IdentitiesOnly yes

# Default fallback
Match host github.com
    IdentityFile ~/.ssh/id_rsa_default

3. Verify Your Configuration

# Test which SSH key will be used
ssh -T git@github.com -v

# Check Git's effective SSH command
git config core.sshCommand

# List all Git configurations
git config --list --show-origin

# Test SSH connection with specific key
ssh -T -i /root/.ssh/repo git@github.com

4. Security Best Practices

Key Permissions

# Set correct permissions for SSH keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa*
chmod 644 ~/.ssh/*.pub
chmod 600 ~/.ssh/config

Use SSH Agent for Passphrase-Protected Keys

# Start SSH agent
eval "$(ssh-agent -s)"

# Add keys to agent (enter passphrase once per session)
ssh-add ~/.ssh/id_rsa_personal
ssh-add ~/.ssh/id_rsa_work

# List loaded keys
ssh-add -l

# Use agent in Git
git config --local core.sshCommand "ssh -o IdentitiesOnly=yes -o ForwardAgent=no"

Regular Key Rotation

# Generate new key with stronger encryption
ssh-keygen -t ed25519 -a 100 -C "your_email@example.com"

# Or RSA with 4096 bits
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

5. Troubleshooting Common Issues

Problem: "Permission denied (publickey)"

# Check if key is added to SSH agent
ssh-add -l

# Test connection with verbose output
ssh -Tv git@github.com

# Verify key is added to GitHub/GitLab
cat ~/.ssh/id_rsa.pub

Problem: Wrong key being used despite configuration

# Ensure IdentitiesOnly is set to prevent SSH from trying other keys
git config --local core.sshCommand "ssh -o IdentitiesOnly=yes -i /path/to/key"

# Check all matching keys
ssh -T git@github.com -v 2>&1 | grep "Offering"

Problem: SSH config not being respected

# Test SSH config parsing
ssh -F /dev/null -G github.com

# Debug SSH config loading
ssh -T git@github.com -F ~/.ssh/config -v

6. Team Collaboration Tips

When working in a team with shared repositories:

# Add to .gitconfig (user-specific, not committed)
git config --local core.sshCommand "ssh -i ~/.ssh/team-key"

# Or use includeIf for conditional includes
git config --global includeIf.gitdir:~/work/.path "~/work/.gitconfig"

Create a README.md section for your team:

## SSH Setup for This Repository

This repository requires a specific SSH key. Set it up with:

```bash
git config --local core.sshCommand "ssh -i ~/.ssh/our-team-key -o IdentitiesOnly=yes"

Or add to your ~/.ssh/config:

Host github.com
    IdentityFile ~/.ssh/our-team-key
    IdentitiesOnly yes

### 7. **Automation Script**

Save this as `setup-git-ssh.sh`:

```bash
#!/bin/bash

# Script to automate Git SSH configuration for a repository

REPO_PATH="${1:-.}"
SSH_KEY="${2}"

if [ -z "$SSH_KEY" ]; then
    echo "Usage: $0 <repository-path> <ssh-key-path>"
    echo "Example: $0 . ~/.ssh/repo"
    exit 1
fi

if [ ! -f "$SSH_KEY" ]; then
    echo "Error: SSH key not found at $SSH_KEY"
    exit 1
fi

cd "$REPO_PATH" || exit 1

if [ ! -d ".git" ]; then
    echo "Error: Not a git repository"
    exit 1
fi

# Set the SSH command
git config --local core.sshCommand "ssh -o IdentitiesOnly=yes -i $SSH_KEY"

# Verify
echo "✅ SSH command configured:"
git config --local core.sshCommand

# Test connection
echo "🔍 Testing connection..."
ssh -T -o IdentitiesOnly=yes -i "$SSH_KEY" git@github.com 2>&1 | grep -q "successfully authenticated" && \
    echo "✅ Authentication successful" || \
    echo "⚠️  Please verify your SSH key is added to your Git provider"

Conclusion

While the quick fix of setting core.sshCommand locally works great for single repositories, implementing proper SSH config management is crucial as your projects grow. The SSH config file approach offers:

  • Centralized management of all SSH keys
  • Automatic key selection based on host or directory
  • Consistent behavior across Git and other SSH commands
  • Better security with per-key options

Start with the repository-specific config for quick wins, then evolve to SSH config files as your key collection grows.


Quick Reference Card

# Single repo setup
git config --local core.sshCommand "ssh -i ~/.ssh/specific-key -o IdentitiesOnly=yes"

# Check current config
git config --local core.sshCommand

# Remove config
git config --local --unset core.sshCommand

# SSH config example
echo 'Host github.com
    IdentityFile ~/.ssh/specific-key
    IdentitiesOnly yes' >> ~/.ssh/config

Remember: The best solution depends on your workflow. For one-off repositories, use git config --local. For power users managing dozens of keys, invest time in ~/.ssh/config.


This blog post covers:
- The main solution with Git config
- Four alternative approaches
- Security best practices
- SSH config file patterns
- Troubleshooting guide
- Team collaboration tips
- An automation script
- Quick reference card