Skill

git-identity

Install
1
Install the plugin
$
npx claudepluginhub melodic-software/claude-code-plugins --plugin git

Want just this skill?

Add to a custom plugin, then install with one command.

Description

Multi-identity Git configuration with directory-scoped isolation. Sets up per-directory user email, GPG signing keys, and SSH keys using includeIf conditional includes. Use when configuring work vs personal Git identities, fixing "Unverified" commits from email/GPG key mismatch, setting up multiple GitHub accounts on one machine, auditing identity isolation, or troubleshooting includeIf, GPG key selection, or SSH key routing issues.

Tool Access

This skill is limited to using the following tools:

ReadBashGlobGrep
Supporting Assets
View in Repository
references/identity-setup-guide.md
references/verification-commands.md
Skill Content

Git Multi-Identity Configuration

Directory-scoped Git identity isolation: automatic email, GPG key, and SSH key selection based on repository location.

Table of Contents

Overview

Multi-identity isolation solves the problem of using different Git identities (email, GPG key, SSH key) across different contexts on the same machine. Instead of manually switching configuration or setting per-repo overrides, includeIf conditional includes automatically apply the correct identity based on which directory a repository lives in.

What this provides:

  • Automatic user.email and user.name per directory tree
  • Automatic GPG signing key selection per identity
  • Automatic SSH key routing per identity (multiple GitHub accounts)
  • Zero manual switching -- commit in any repo and the correct identity applies

When to Use This Skill

  • Setting up work vs personal Git identities on the same machine
  • Configuring multiple GitHub/GitLab accounts with different SSH keys
  • Fixing "Unverified" commits caused by email/GPG key mismatch
  • Auditing that identity isolation is working correctly across directories
  • Troubleshooting includeIf not matching, wrong GPG key used, or SSH "permission denied"
  • Adding a new identity (new employer, new open-source persona)

Gather User Details First

Before executing any setup commands, use AskUserQuestion to collect the user's specific details. Every identity setup is unique -- do not assume directory paths, email addresses, or identity names.

Required information per identity:

  1. Identity name (e.g., "work", "personal", "freelance", "open-source")
  2. Directory path where repos for this identity live (e.g., ~/Projects/work/)
  3. Git email for this identity
  4. Git name (if different per identity, or one shared name)
  5. GPG signing? Whether they want GPG signing (and whether keys already exist)
  6. SSH key routing? Whether they need separate SSH keys per identity (e.g., multiple GitHub accounts)
  7. Platform (Windows, macOS, Linux) -- determines gitdir: vs gitdir/i: syntax

Example AskUserQuestion flow:

  • "How many Git identities do you need? What are their names (e.g., work, personal)?"
  • "What directory contains your [identity] repositories?"
  • "What email address should be used for [identity] commits?"
  • "Do you already have GPG keys for each identity, or should we generate them?"
  • "Do you use multiple GitHub/GitLab accounts (requiring separate SSH keys)?"

Only proceed with setup commands after collecting these details. Replace all placeholder values in the examples below with the user's actual values.

Quick Start

Minimal end-to-end setup for two identities (work + personal):

# 1. Create directory-scoped gitconfig files
cat > ~/.gitconfig-work << 'EOF'
[user]
    email = jane@acme-corp.com
    signingkey = <WORK_GPG_KEY_ID>
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_work
EOF

cat > ~/.gitconfig-personal << 'EOF'
[user]
    email = jane@example.com
    signingkey = <PERSONAL_GPG_KEY_ID>
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_personal
EOF

# 2. Add includeIf directives to ~/.gitconfig
# (Windows: use gitdir/i: for case-insensitive matching)
git config --global --add includeIf."gitdir/i:C:/Projects/work/".path ~/.gitconfig-work
git config --global --add includeIf."gitdir/i:C:/Projects/personal/".path ~/.gitconfig-personal

# 3. Verify
cd ~/Projects/work/any-repo && git config user.email
# Expected: jane@acme-corp.com

cd ~/Projects/personal/any-repo && git config user.email
# Expected: jane@example.com

For complete step-by-step setup, see references/identity-setup-guide.md.

Setup

Directory Layout Convention

Organize repositories by identity under a common parent:

~/Projects/
    work/           # All work repositories
        repo-a/
        repo-b/
    personal/       # All personal repositories
        my-project/
        dotfiles/

The parent directory (e.g., work/, personal/) is what includeIf gitdir matches against. Ask the user for their actual directory layout -- do not assume paths.

Per-Identity Gitconfig Files

Create a separate gitconfig file for each identity. Each file overrides user.email, user.name (if different), user.signingkey, and optionally core.sshCommand.

Work identity (~/.gitconfig-work):

[user]
    email = jane@acme-corp.com
    signingkey = ABC123DEF4567890
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_work

Personal identity (~/.gitconfig-personal):

[user]
    email = jane@example.com
    signingkey = 1234567890ABCDEF
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_personal

includeIf Directives

Add conditional includes to ~/.gitconfig:

[user]
    name = Jane Developer
[commit]
    gpgsign = true

# Identity isolation
[includeIf "gitdir/i:C:/Projects/work/"]
    path = ~/.gitconfig-work
[includeIf "gitdir/i:C:/Projects/personal/"]
    path = ~/.gitconfig-personal

Critical rules:

  • Trailing slash required -- gitdir:C:/Projects/work/ not gitdir:C:/Projects/work
  • Windows: use gitdir/i: -- case-insensitive matching (Windows paths are case-insensitive)
  • macOS/Linux: use gitdir: -- case-sensitive matching is fine on case-sensitive filesystems
  • The user.name in the main config acts as default; per-identity files only need to override what differs

GPG Key Per Identity

Generate a separate GPG key for each identity email. See git:gpg-signing for detailed key generation.

# Generate work key (use work email)
gpg --full-generate-key
# Email: jane@acme-corp.com

# Generate personal key (use personal email)
gpg --full-generate-key
# Email: jane@example.com

# List keys to get IDs
gpg --list-secret-keys --keyid-format=long

Put the corresponding key ID in each identity's gitconfig file under user.signingkey.

SSH Key Per Identity

Generate a separate SSH key for each identity:

# Work SSH key
ssh-keygen -t ed25519 -C "jane@acme-corp.com" -f ~/.ssh/id_ed25519_work

# Personal SSH key
ssh-keygen -t ed25519 -C "jane@example.com" -f ~/.ssh/id_ed25519_personal

Two routing approaches (pick one):

Option A: core.sshCommand in per-identity gitconfig (recommended -- simpler):

# In ~/.gitconfig-work
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_work

Option B: ~/.ssh/config Host-based routing (needed for multiple GitHub accounts):

# ~/.ssh/config
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_personal
    IdentitiesOnly yes

With Host-based routing, use url.insteadOf in each identity config to transparently rewrite remote URLs:

# In ~/.gitconfig-work
[url "git@github-work:"]
    insteadOf = git@github.com:

See references/identity-setup-guide.md for complete SSH routing details.

Adding Keys to GitHub

Each identity's SSH and GPG public keys must be uploaded to the corresponding GitHub account:

  1. SSH key: Settings > SSH and GPG keys > New SSH key
  2. GPG key: Settings > SSH and GPG keys > New GPG key (gpg --armor --export <KEY_ID>)
  3. Verify email: The email on the GPG key must be a verified email on the GitHub account

Audit

Verify identity isolation is working correctly across all directories.

Check Effective Identity

# Check effective identity in any directory
cd /path/to/repo
git config user.email
git config user.name
git config user.signingkey
git config core.sshCommand

# Show where each value comes from
git config --show-origin user.email
git config --show-origin user.signingkey

Detect Mismatches

# Compare Git email vs GPG key email
GIT_EMAIL=$(git config user.email)
KEY_ID=$(git config user.signingkey)
GPG_EMAIL=$(gpg --list-keys "$KEY_ID" 2>/dev/null | grep -oP '<\K[^>]+')
if [ "$GIT_EMAIL" != "$GPG_EMAIL" ]; then
    echo "MISMATCH: Git=$GIT_EMAIL GPG=$GPG_EMAIL"
else
    echo "OK: $GIT_EMAIL"
fi

Audit All Identity Directories

Ask the user which directories to audit, then check each:

# Check identity directories (replace with user's actual paths)
for dir in ~/Projects/work ~/Projects/personal; do
    echo "=== $dir ==="
    git -C "$dir/$(ls "$dir" | head -1)" config user.email
    git -C "$dir/$(ls "$dir" | head -1)" config user.signingkey
done

See references/verification-commands.md for comprehensive verification scripts.

Troubleshoot

"Unverified" Commits on GitHub

Cause: The email in the commit signature does not match a verified email on the GitHub account, or the GPG public key is not uploaded.

Diagnosis:

# Check what email was used in the commit
git log --format='%ae %GK %G?' -1

# %ae = author email, %GK = signing key, %G? = signature status
# G = good, B = bad, N = no signature, U = untrusted

Fixes:

  1. Upload GPG public key to GitHub (Settings > SSH and GPG keys)
  2. Ensure Git email matches GPG key email matches GitHub verified email
  3. Re-sign past commits if needed: git rebase --exec 'git commit --amend --no-edit -S' HEAD~N

includeIf Not Matching

Symptoms: git config user.email shows global default instead of per-directory value.

Common causes:

  1. Missing trailing slash: gitdir:C:/Projects/work must be gitdir:C:/Projects/work/
  2. Case sensitivity on Windows: Use gitdir/i: instead of gitdir:
  3. Path format mismatch: Use forward slashes on all platforms; Git normalizes internally
  4. Not inside a git repo: includeIf gitdir only activates inside a git repository

Diagnosis:

# Show all config with origins -- look for the includeIf file
git config --list --show-origin | grep -i "user\."

# Verify the includeIf directive
git config --global --list | grep includeIf

Wrong GPG Key Used

Symptoms: Commits signed with wrong key; "Unverified" despite key being uploaded.

Diagnosis:

# Check which key Git is using in this directory
git config user.signingkey

# Check which includeIf file is providing it
git config --show-origin user.signingkey

# Verify the key exists
gpg --list-secret-keys --keyid-format=long $(git config user.signingkey)

SSH Permission Denied (Wrong Key Offered)

Symptoms: git push fails with "Permission denied (publickey)" despite having SSH keys.

Diagnosis:

# Check which SSH command Git is using
git config core.sshCommand

# Test SSH connection with verbose output
ssh -vT git@github.com 2>&1 | grep "Offering"

# If using Host-based routing, test the specific host alias
ssh -vT git@github-work 2>&1 | grep "Offering"

Fixes:

  1. Verify core.sshCommand points to correct key file
  2. Verify ~/.ssh/config has IdentitiesOnly yes to prevent SSH agent from offering wrong keys
  3. Verify the SSH key is added to the correct GitHub account

Architecture

How includeIf Works

Git's includeIf evaluates conditions when reading configuration. For gitdir:

  1. Git determines the current repository's .git directory path
  2. It normalizes the path (resolves symlinks, uses forward slashes)
  3. It checks if the normalized path starts with the gitdir pattern
  4. If matched, the referenced file is included and its settings override earlier values

Config precedence with includeIf:

System config (/etc/gitconfig)
  -> Global config (~/.gitconfig)
    -> includeIf matched files (in order they appear)
      -> Local config (.git/config)

Local config (.git/config) still has highest priority. An includeIf file sits between global and local.

Multiple includeIf Files

If multiple includeIf directives match, they are all included in order. Later includes override earlier ones for the same settings.

gitdir vs gitdir/i

VariantCase SensitivityUse On
gitdir:Case-sensitivemacOS (APFS), Linux (ext4)
gitdir/i:Case-insensitiveWindows (NTFS), macOS (HFS+)

Always use gitdir/i: on Windows. On macOS, use gitdir/i: unless you know the filesystem is case-sensitive.

Related Skills

  • gpg-signing: GPG key generation, passphrase caching, platform setup, and troubleshooting
  • git-config: Configuration hierarchy, aliases, credentials, and performance tuning
  • setup: Git installation, initial configuration, and platform-specific setup

Version History

  • v1.0.0 (2026-02-16): Initial release -- multi-identity isolation with includeIf, GPG, SSH, audit, and troubleshooting

Last Updated

Date: 2026-02-16 Model: claude-opus-4-6

Stats
Stars40
Forks6
Last CommitFeb 16, 2026
Actions

Similar Skills

cache-components

Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.

138.4k