Git多身份配置Skill git-identity

Git多身份配置技能通过includeIf条件包含实现目录范围的Git身份隔离,自动应用正确的身份设置,包括用户邮箱、GPG密钥和SSH密钥。适用于工作与个人Git身份分离、多GitHub账户管理、修复提交验证问题等场景,提升开发效率。关键词:Git配置、多身份、目录隔离、includeIf、GPG签名、SSH密钥、GitHub账户。

DevOps 0 次安装 0 次浏览 更新于 3/11/2026

名称: git-identity 描述: 基于目录范围隔离的Git多身份配置。通过includeIf条件包含设置每目录用户邮箱、GPG签名密钥和SSH密钥。适用于配置工作与个人Git身份、修复因邮箱/GPG密钥不匹配导致的“未验证”提交、在一台机器上设置多个GitHub账户、审计身份隔离效果或排查includeIf、GPG密钥选择或SSH密钥路由问题。 允许工具: 读取, Bash, Glob, Grep

Git多身份配置

目录范围的Git身份隔离:基于仓库位置自动选择邮箱、GPG密钥和SSH密钥。

目录

概述

多身份隔离解决了在同一台机器上跨不同上下文使用不同Git身份(邮箱、GPG密钥、SSH密钥)的问题。通过includeIf条件包含,基于仓库所在目录自动应用正确的身份设置,无需手动切换配置或设置每个仓库的覆盖。

此技能提供:

  • 每个目录树的自动user.emailuser.name设置
  • 每个身份的自动GPG签名密钥选择
  • 每个身份的自动SSH密钥路由(多个GitHub账户)
  • 零手动切换——在任何仓库提交时自动应用正确身份

何时使用此技能

  • 在同一台机器上设置工作与个人Git身份
  • 配置具有不同SSH密钥的多个GitHub/GitLab账户
  • 修复因邮箱/GPG密钥不匹配导致的“未验证”提交
  • 审计跨目录的身份隔离是否正常工作
  • 排查includeIf不匹配、使用错误GPG密钥或SSH“权限被拒绝”问题
  • 添加新身份(如新雇主、新开源身份)

首先收集用户详情

在执行任何设置命令之前,使用AskUserQuestion收集用户的具体详情。每个身份设置都是唯一的——不要假设目录路径、邮箱地址或身份名称。

每个身份所需信息:

  1. 身份名称(例如,“工作”、“个人”、“自由职业”、“开源”)
  2. 目录路径,该身份仓库所在位置(例如,~/Projects/work/
  3. Git邮箱用于此身份
  4. Git名称(如果每个身份不同,或共享一个名称)
  5. **GPG签名?**是否想要GPG签名(以及密钥是否已存在)
  6. **SSH密钥路由?**是否需要每个身份单独的SSH密钥(例如,多个GitHub账户)
  7. 平台(Windows、macOS、Linux)——决定gitdir:gitdir/i:语法

示例AskUserQuestion流程:

  • “您需要多少个Git身份?它们的名称是什么(例如,工作、个人)?”
  • “哪个目录包含您的[身份]仓库?”
  • “哪个邮箱地址应用于[身份]提交?”
  • “您是否已经拥有每个身份的GPG密钥,或者我们应该生成它们?”
  • “您是否使用多个GitHub/GitLab账户(需要单独的SSH密钥)?”

收集这些详情后才继续设置命令。替换下面示例中的所有占位值为用户的实际值。

快速开始

两个身份(工作 + 个人)的最小端到端设置:

# 1. 创建目录范围的gitconfig文件
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. 添加includeIf指令到~/.gitconfig
# (Windows:使用gitdir/i:进行不区分大小写匹配)
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. 验证
cd ~/Projects/work/any-repo && git config user.email
# 预期: jane@acme-corp.com

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

完整逐步设置,参见references/identity-setup-guide.md

设置

目录布局约定

按身份在公共父目录下组织仓库:

~/Projects/
    work/           # 所有工作仓库
        repo-a/
        repo-b/
    personal/       # 所有个人仓库
        my-project/
        dotfiles/

父目录(例如,work/personal/)是includeIf gitdir匹配的对象。询问用户的实际目录布局——不要假设路径。

每个身份的Gitconfig文件

为每个身份创建单独的gitconfig文件。每个文件覆盖user.emailuser.name(如果不同)、user.signingkey,并可选的core.sshCommand

工作身份 (~/.gitconfig-work):

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

个人身份 (~/.gitconfig-personal):

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

includeIf指令

添加条件包含到~/.gitconfig

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

# 身份隔离
[includeIf "gitdir/i:C:/Projects/work/"]
    path = ~/.gitconfig-work
[includeIf "gitdir/i:C:/Projects/personal/"]
    path = ~/.gitconfig-personal

关键规则:

  • 必须包含尾随斜杠——gitdir:C:/Projects/work/而不是gitdir:C:/Projects/work
  • Windows:使用gitdir/i:——不区分大小写匹配(Windows路径不区分大小写)
  • macOS/Linux:使用gitdir:——在区分大小写的文件系统上,区分大小写匹配即可
  • 主配置中的user.name作为默认值;每个身份文件仅需覆盖不同部分

每个身份的GPG密钥

为每个身份邮箱生成单独的GPG密钥。参见git:gpg-signing获取详细密钥生成指南。

# 生成工作密钥(使用工作邮箱)
gpg --full-generate-key
# 邮箱: jane@acme-corp.com

# 生成个人密钥(使用个人邮箱)
gpg --full-generate-key
# 邮箱: jane@example.com

# 列出密钥以获取ID
gpg --list-secret-keys --keyid-format=long

将相应密钥ID放入每个身份的gitconfig文件的user.signingkey下。

每个身份的SSH密钥

为每个身份生成单独的SSH密钥:

# 工作SSH密钥
ssh-keygen -t ed25519 -C "jane@acme-corp.com" -f ~/.ssh/id_ed25519_work

# 个人SSH密钥
ssh-keygen -t ed25519 -C "jane@example.com" -f ~/.ssh/id_ed25519_personal

两种路由方法(选择一种):

选项A:在身份gitconfig中使用core.sshCommand(推荐——更简单):

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

选项B:基于主机的~/.ssh/config路由(需要多个GitHub账户):

# ~/.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

使用基于主机的路由时,在每个身份配置中使用url.insteadOf透明重写远程URL:

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

参见references/identity-setup-guide.md获取完整SSH路由详情。

添加密钥到GitHub

每个身份的SSH和GPG公钥必须上传到相应的GitHub账户:

  1. SSH密钥:设置 > SSH和GPG密钥 > 新SSH密钥
  2. GPG密钥:设置 > SSH和GPG密钥 > 新GPG密钥(gpg --armor --export <KEY_ID>
  3. 验证邮箱:GPG密钥上的邮箱必须是GitHub账户上的已验证邮箱

审计

验证身份隔离在所有目录中正常工作。

检查有效身份

# 在任何目录检查有效身份
cd /path/to/repo
git config user.email
git config user.name
git config user.signingkey
git config core.sshCommand

# 显示每个值的来源
git config --show-origin user.email
git config --show-origin user.signingkey

检测不匹配

# 比较Git邮箱与GPG密钥邮箱
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 "不匹配: Git=$GIT_EMAIL GPG=$GPG_EMAIL"
else
    echo "OK: $GIT_EMAIL"
fi

审计所有身份目录

询问用户要审计的目录,然后检查每个:

# 检查身份目录(替换为用户的实际路径)
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

参见references/verification-commands.md获取全面验证脚本。

故障排查

GitHub上“未验证”提交

原因: 提交签名中的邮箱与GitHub账户上的已验证邮箱不匹配,或GPG公钥未上传。

诊断:

# 检查提交中使用的邮箱
git log --format='%ae %GK %G?' -1

# %ae = 作者邮箱, %GK = 签名密钥, %G? = 签名状态
# G = 好, B = 坏, N = 无签名, U = 不信任

修复:

  1. 上传GPG公钥到GitHub(设置 > SSH和GPG密钥)
  2. 确保Git邮箱匹配GPG密钥邮箱匹配GitHub已验证邮箱
  3. 如有需要,重新签名过去提交:git rebase --exec 'git commit --amend --no-edit -S' HEAD~N

includeIf不匹配

症状: git config user.email显示全局默认值而不是每个目录值。

常见原因:

  1. 缺少尾随斜杠gitdir:C:/Projects/work必须为gitdir:C:/Projects/work/
  2. Windows上的区分大小写:使用gitdir/i:而不是gitdir:
  3. 路径格式不匹配:在所有平台使用正斜杠;Git内部规范化
  4. 不在git仓库内includeIf gitdir仅在git仓库内激活

诊断:

# 显示所有配置及其来源——查找includeIf文件
git config --list --show-origin | grep -i "user\."

# 验证includeIf指令
git config --global --list | grep includeIf

使用错误GPG密钥

症状: 提交使用错误密钥签名;尽管密钥已上传,仍“未验证”。

诊断:

# 检查在此目录中Git使用哪个密钥
git config user.signingkey

# 检查哪个includeIf文件提供它
git config --show-origin user.signingkey

# 验证密钥是否存在
gpg --list-secret-keys --keyid-format=long $(git config user.signingkey)

SSH权限被拒绝(提供错误密钥)

症状: 尽管有SSH密钥,git push失败并显示“权限被拒绝(公钥)”。

诊断:

# 检查Git使用哪个SSH命令
git config core.sshCommand

# 使用详细输出测试SSH连接
ssh -vT git@github.com 2>&1 | grep "Offering"

# 如果使用基于主机的路由,测试特定主机别名
ssh -vT git@github-work 2>&1 | grep "Offering"

修复:

  1. 验证core.sshCommand指向正确密钥文件
  2. 验证~/.ssh/configIdentitiesOnly yes以防止SSH代理提供错误密钥
  3. 验证SSH密钥已添加到正确的GitHub账户

架构

includeIf如何工作

Git的includeIf在读取配置时评估条件。对于gitdir

  1. Git确定当前仓库的.git目录路径
  2. 它规范化路径(解析符号链接,使用正斜杠)
  3. 检查规范化路径是否以gitdir模式开头
  4. 如果匹配,则包含引用文件,其设置覆盖先前值

includeIf的配置优先级:

系统配置 (/etc/gitconfig)
  -> 全局配置 (~/.gitconfig)
    -> includeIf匹配文件(按出现顺序)
      -> 本地配置 (.git/config)

本地配置(.git/config)仍有最高优先级。includeIf文件位于全局和本地之间。

多个includeIf文件

如果多个includeIf指令匹配,它们都按顺序包含。对于相同设置,后来者覆盖先前者。

gitdir vs gitdir/i

变体 区分大小写 使用于
gitdir: 区分大小写 macOS(APFS)、Linux(ext4)
gitdir/i: 不区分大小写 Windows(NTFS)、macOS(HFS+)

Windows上始终使用gitdir/i:。macOS上,除非知道文件系统区分大小写,否则使用gitdir/i:

相关技能

  • gpg-signing:GPG密钥生成、口令缓存、平台设置和故障排查
  • git-config:配置层次、别名、凭证和性能调优
  • setup:Git安装、初始配置和平台特定设置

版本历史

  • v1.0.0 (2026-02-16):初始发布——包含includeIf、GPG、SSH、审计和故障排查的多身份隔离

最后更新

日期: 2026-02-16 模型: claude-opus-4-6