一台机器配置多个 GitHub 账号

#工具 #Git #GitHub 共 2,022 字 约 5 分钟

一台开发机上同时维护个人项目和工作项目,提交记录希望用不同的 GitHub 账号。不想每次 clone 后手动改 user.email,也不想搞全局切换脚本。SSH 密钥隔离 + Git 条件配置就能解决,配完一劳永逸。

1. 场景

典型需求:

  • 个人项目~/personal/*)用个人 GitHub 账号提交
  • 工作项目~/work/*)用公司 GitHub 账号提交
  • 每个账号有独立的 SSH 密钥,互不干扰
  • 进入不同目录自动切换身份,无需手动配置

额外痛点:

  • 公司网络可能封 SSH 默认端口 22,需要走 443
  • 有些项目需要用别名(如 work.github.com)区分 remote URL

2. 整体思路

三层配置协同工作:

  1. SSH 层~/.ssh/config):为不同账号配置独立密钥和 Host 别名
  2. Git 全局层~/.gitconfig):设置默认账号和 SSH 命令
  3. Git 条件层~/.gitconfig-work):按目录路径自动覆盖账号信息

关键机制:includeIf 让 Git 在特定目录下加载额外配置文件。

3. 步骤

3.1 生成 SSH 密钥对

为每个账号生成独立密钥:

# 个人账号密钥
ssh-keygen -t rsa -b 4096 -C "personal@example.com" -f ~/.ssh/id_rsa_personal

# 工作账号密钥
ssh-keygen -t rsa -b 4096 -C "work@company.com" -f ~/.ssh/id_rsa_work

生成后会得到:

  • ~/.ssh/id_rsa_personal + ~/.ssh/id_rsa_personal.pub
  • ~/.ssh/id_rsa_work + ~/.ssh/id_rsa_work.pub

.pub 公钥分别添加到对应 GitHub 账号的 SSH keys 设置页面。

3.2 配置 SSH Host 别名

编辑 ~/.ssh/config(没有则创建):

# 个人账号(默认)
Host github.com
  HostName ssh.github.com
  User git
  IdentityFile ~/.ssh/id_rsa_personal
  Port 443

# 工作账号(使用别名 work.github.com)
Host work.github.com
  HostName ssh.github.com
  User git
  IdentityFile ~/.ssh/id_rsa_work
  Port 443

重点说明

  • Port 443:绕过防火墙对 22 端口的封锁,GitHub 官方支持 ssh.github.com:443
  • Host 别名work.github.com 是本地别名,实际连接的还是 ssh.github.com
  • IdentityFile:指定使用哪个密钥

测试连接:

# 测试个人账号
ssh -T git@github.com
# 预期输出:Hi personal-username! You've successfully authenticated...

# 测试工作账号
ssh -T git@work.github.com
# 预期输出:Hi work-username! You've successfully authenticated...

3.3 配置 Git 全局默认

编辑 ~/.gitconfig

[user]
  name = Your Name
  email = personal@example.com

[core]
  # 全局强制使用个人账号密钥
  sshCommand = ssh -i ~/.ssh/id_rsa_personal -F /dev/null

# 条件配置:work 目录自动切换账号
[includeIf "gitdir:~/work/"]
  path = ~/.gitconfig-work

关键点

  • sshCommand 强制使用指定密钥,-F /dev/null 阻止 ~/.ssh/config 干扰(可选,取决于你的优先级策略)
  • includeIf 匹配路径时,gitdir: 后的路径必须以 / 结尾才能匹配子目录
  • 路径支持 ~ 展开和通配符 *

3.4 配置工作账号条件文件

创建 ~/.gitconfig-work

[user]
  name = Your Name
  email = work@company.com

[core]
  sshCommand = ssh -i ~/.ssh/id_rsa_work -F /dev/null

现在逻辑是:

  • 默认用个人账号(~/.gitconfig
  • 进入 ~/work/ 任何子目录,自动切换到工作账号(~/.gitconfig-work 覆盖)

3.5 使用 Host 别名 clone 工作项目

工作项目 clone 时需要修改 URL:

# 原始 URL(会用个人账号)
git clone git@github.com:company/project.git

# 改用 Host 别名(会用工作账号密钥)
git clone git@work.github.com:company/project.git

或者 clone 后修改 remote:

git remote set-url origin git@work.github.com:company/project.git

为什么需要别名?

即使在 ~/work/ 目录下,如果 remote URL 是 git@github.com,SSH 会优先匹配 ~/.ssh/config 中的 Host github.com 配置。Host 别名让你在 URL 层面就区分账号。

4. 验证配置

4.1 检查当前目录生效的配置

# 在个人项目目录
cd ~/personal/my-project
git config user.email
# 输出:personal@example.com

# 在工作项目目录
cd ~/work/company-project
git config user.email
# 输出:work@company.com

4.2 检查 SSH 连接使用的密钥

# 查看实际使用的 SSH 命令
git config core.sshCommand

# 手动测试(带详细日志)
GIT_SSH_COMMAND="ssh -v" git ls-remote origin
# 输出中会显示 "Offering public key: /path/to/id_rsa_xxx"

4.3 测试提交身份

# 创建测试提交
echo "test" > test.txt
git add test.txt
git commit -m "test commit"

# 查看提交的 author
git log -1 --format="%an <%ae>"

5. 常见问题

5.1 端口 22 被墙

症状:ssh -T git@github.com 超时

解决:在 ~/.ssh/config 中添加:

Host github.com
  HostName ssh.github.com
  Port 443

GitHub 官方在 ssh.github.com 的 443 端口提供 SSH 服务,专门用于绕过防火墙。

5.2 密钥权限问题

症状:Permissions 0644 for 'id_rsa_work' are too open

解决:

chmod 600 ~/.ssh/id_rsa_*
chmod 644 ~/.ssh/id_rsa_*.pub

私钥必须只有所有者可读写(600),公钥可以宽松一些(644)。

5.3 includeIf 不生效

检查清单:

  1. 路径必须以 / 结尾gitdir:~/work/(对)vs gitdir:~/work(错)
  2. Git 版本includeIf 需要 Git 2.13+,运行 git --version 确认
  3. 路径展开~ 会展开,但相对路径不会,建议用绝对路径或 ~/
  4. 调试:运行 git config --show-origin user.email 查看配置来源

5.4 已有项目切换账号

如果项目已经用错误账号提交过:

# 1. 修改 remote URL(如果需要)
git remote set-url origin git@work.github.com:company/project.git

# 2. 修改最近一次提交的 author(如果还没 push)
git commit --amend --reset-author

# 3. 批量修改历史提交(慎用,会改写历史)
git filter-branch --env-filter '
if [ "$GIT_COMMITTER_EMAIL" = "wrong@example.com" ]; then
  export GIT_COMMITTER_EMAIL="correct@example.com"
  export GIT_AUTHOR_EMAIL="correct@example.com"
fi
' --tag-name-filter cat -- --branches --tags

6. 进阶:更细粒度的控制

6.1 按项目单独配置

如果某个项目需要特殊配置,在项目内运行:

git config user.email "special@example.com"
git config core.sshCommand "ssh -i ~/.ssh/id_rsa_special"

项目级配置(.git/config)优先级最高,会覆盖全局和条件配置。

6.2 多个工作目录

如果有多个工作目录:

[includeIf "gitdir:~/work/"]
  path = ~/.gitconfig-work

[includeIf "gitdir:~/company-a/"]
  path = ~/.gitconfig-company-a

[includeIf "gitdir:~/company-b/"]
  path = ~/.gitconfig-company-b

6.3 HTTPS 协议多账号

本文聚焦 SSH,但 HTTPS 也可以多账号:

  • macOS Keychain 存储凭据,git-credential-osxkeychain 管理
  • 或用 GitHub CLI:gh auth login 支持多账号切换
  • 条件配置中可以设置不同的 credential.helper

7. 总结

配置后的工作流:

  1. 个人项目放在 ~/personal/,自动用个人账号
  2. 工作项目放在 ~/work/,自动用工作账号
  3. Clone 工作项目时记得用 git@work.github.com
  4. 忘记配置也没关系,提交前 git config user.email 检查一下

核心收益:

  • 零手动切换:进入目录自动生效
  • 隔离彻底:密钥、身份、目录三层隔离
  • 可验证:每步都有明确的测试方法

这套配置用了两年,再没有提交记录用错账号的情况。