同一台电脑使用两个 GitHub 账号

摘要

三处配置各管一件事

个人账号和公司账号如果共用一把 SSH 密钥、一个 user.email、一次 gh 登录,公司仓库里的提交会写上个人邮箱,推送或 gh pr create 也会走到另一个账号,对方直接拒绝。

推送走哪把密钥,由远程地址和 ~/.ssh/config 决定。提交记录里的姓名和邮箱,由 Git 配置决定。gh pr create 用哪个账号,由 gh 的活动账号决定。三处要分别设好。只配其中一处时,另外两处仍是原来的账号。

远程地址以 git@ 开头才会读 ~/.ssh/config。https://github.com/... 走凭据助手,同一主机名在钥匙串里通常只留一套凭据。两个账号的仓库改用下面的 SSH 地址。

SSH:两把密钥

个人账号继续用已有的 ~/.ssh/id_ed25519。公司账号另生成一把,-f 指定文件名,避免覆盖个人密钥。

1
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "work@example.com"

把 ~/.ssh/id_ed25519.pub 加到个人账号,把 ~/.ssh/id_ed25519_work.pub 加到公司账号。网页入口是头像 → Settings → SSH and GPG keys → New SSH key,类型选 Authentication Key。也可以在对应账号已登录 gh 时执行:

1
2
# --type 默认是 authentication。公钥加到当前 gh 活动账号
gh ssh-key add ~/.ssh/id_ed25519_work.pub --type authentication --title "work laptop"

~/.ssh/config 里用两个 Host 区分。IdentitiesOnly yes 让这次连接只出示指定的那把密钥。文件里已经有 Host github.com 时,只在那一段补上 IdentitiesOnly yes 和对应的 IdentityFile,不要再写一段同名的 Host。SSH 对每个参数采用先出现的值,后面的同名配置不会盖过前面。已有 Host * 时,把具体的 Host 放在它前面。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 个人账号。已有的 git@github.com:用户/仓库.git 继续走这里
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes

# 公司账号。远程要写成 git@github-work:组织/仓库.git
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes

这两段写进文件,新开的终端同样生效。

1
2
ssh -T git@github.com
ssh -T git@github-work

成功时输出 Hi 用户名! You've successfully authenticated。两个命令应该打出不同的用户名。打出同一个用户名时,先看对应 Host 的 IdentityFile 是不是指错了文件。

已克隆的公司仓库改远程地址。这条写入该仓库的 .git/config。

1
2
git remote set-url origin git@github-work:组织/仓库.git
git remote -v

新克隆直接用别名:

1
git clone git@github-work:组织/仓库.git

按目录切换姓名和邮箱

个人资料留在 ~/.gitconfig。公司仓库统一放在 ~/work/ 下,另写一份 ~/.gitconfig-work,再让 Git 在这个目录里改用它。

worktree/i: 按工作区目录匹配,末尾的 / 会连带匹配其中的子目录。i 表示大小写不敏感,适合 macOS。目录本身是符号链接时,按 git rev-parse --show-toplevel 打出的真实路径来写。

在 ~/.gitconfig 末尾追加:

1
2
[includeIf "worktree/i:~/work/"]
path = ~/.gitconfig-work

~/.gitconfig-work:

1
2
3
[user]
name = 公司用的名字
email = work@example.com

这是文件里的配置,不随终端关闭消失。~/work/ 以外的仓库仍用 ~/.gitconfig 里的姓名和邮箱。

到一个公司仓库里核对。来源路径应是 ~/.gitconfig-work。仍显示 ~/.gitconfig 时,说明 includeIf 没有配上,先看 git rev-parse --show-toplevel 是不是落在 ~/work/ 下面。

1
2
git config --show-origin --get user.email
git rev-parse --show-toplevel

公司账号要单独签名时,把 signingkey 也写进 ~/.gitconfig-work。步骤见 用 SSH 密钥签名 Git 提交。

gh 的活动账号

在已经登录个人账号的前提下,再执行一次 gh auth login,按提示登录公司账号。两次都是 github.com。令牌写入凭据库,不只影响当前进程。

1
2
gh auth login
gh auth status

gh auth status 列出该主机上的全部账号,并标出当前活动的那一个。两个账号时,不带 --user 会切到另一个。账号更多时写出用户名:

1
2
gh auth switch --user 公司用户名
gh auth status

当前 shell 设置了环境变量 GH_TOKEN 时,gh 用这张令牌,gh auth switch 选中的账号不会被用到。

ssh -T 能打出公司用户名,只说明这把密钥被 GitHub 接受。紧接着的 gh pr create 用的是活动账号。先看 gh auth status,再看环境里有没有 GH_TOKEN。