当我们有多个 SSH 账号时,会遇到需要使用不同 SSH 账号登录不同的远程服务器,或 push 不同的远程仓库的情况,比如:
- github 的用户名为 user_gh, 邮箱地址为 user_gh@gmail.com,私钥为 id_rsa_gh
- gitlab 的用户名为 user_gl,邮箱地址为 user_gl@gmail.com,私钥为 id_rsa_gl
如何在每次 push/pull/远程登录时自动匹配这些信息呢?笔者说下常用的解决方案。
多个用户信息的配置
在使用 git 推送代码到远程仓库时,若不同仓库的用户名不同,可将最常用的用户名设置为全局用户名,不常用的用户名单独在指定仓库进行设置。
全局设置
执行如下命令进行全局设置:
git config --global user.name "user_gh"
git config --global user.email "user_gh@gmail.com"
也可以编辑 ~/.gitconfig,设置如下:
[user]
name = user_gh
email = user_gh@gmail.com
指定设置
在指定仓库下执行如下命令:
git config user.name "user_gh"
git config user.email "user_gh@gmail.com"
也可以编辑该仓库下的 .git/config,设置如下:
[user]
name = user_gh
email = user_gh@gmail.com
多个 SSH key 的配置
如何让不同的 SSH key 自动识别不同的目标地址呢?笔者以开头的需求为例,说下配置 git 的过程,若需求是访问远程服务器,配置相似。
生成 SSH key
使用 ssh-keygen 命令生成公私钥,一般常用的参数如下:
- -b:指定 key 的 bit 数,对于 RSA key 而言,默认是 3072 bits
- -f:指定 key 的文件名,若需要指定路径,则文件名需要和路径一直,如 ~/.ssh/id_rsa_gh
- -C:指定新的 comment,即公钥末尾的字符串,一般是邮箱地址,若不指定会是 username@hostname 的形式
- -t:指定私钥类型,一般有 "dsa", "ecdsa", "ecdsa-sk", "ed25519", "ed25519-sk" 和 "rsa" 等几种,若指定为 rsa 还可以指定签名类型,默认为 "rsa-sha2-512"
如为 github.com 生成新 SSH key,key 名为 id_rsa_gh:
> ssh-keygen -f ~/.ssh/id_rsa_gh -C user_gh@gmail.com
> ls -l
id_rsa
id_rsa.pub
id_rsa_gh
id_rsa_gh.pub
注意:若已有 ~/.ssh/id_rsa 和 ~/.ssh/id_rsa.pub,建议先对这两个文件进行备份,防止误操作覆盖了这两个文件。
将生成的 SSH 公钥(~/.ssh/id_rsa_gh.pub)内容添加到 github(Settings > SSH and GPG keys > New SSH key)中。若是要登录远程服务器,将公钥添加到远程服务器的 ~/.ssh/authorized_keys 文件中。
使用 ssh-agent 管理 SSH key
在使用上述 SSH key push 文件到 github 时可能会提示 ERROR: Permission to qileq/x.git denied to some-username,这里的用户名 "some-username" 可能不是 .git/config 设置的用户名。类似的若是 ssh 登录远程服务器,可能仍需要输入密码。这两个问题的原因可能是未使用正确的 SSH 私钥,这个问题可以通过 ssh-agent 来解决。
ssh-agent 是一个管理 SSH key 的后台辅助程序,它将私钥加载到内存中,避免每次使用私钥时都需要输入密码,自动加载 ~/.ssh/id_rsa、 ~/.ssh/id_dsa 和 ~/.ssh/id_ecdsa 等各类型的默认私钥,这就是为什么我们不需要显式将 ~/.ssh/id_rsa 添加到 ssh-agent,却能访问远程服务器的原因。当 client 通过 ssh 连接到远程服务器时(或请求 github 时),服务器端会发送验证请求来识别 client 的身份,此时 client 会将验证请求转发给 ssh-agent,ssh-agent 根据配置查找已加载的私钥,然后将私钥处理过后的验证数据发送给 server 进行验证。从某种程序上来讲,ssh-agent 是 SSO 的一种实现。
ssh-agent 通过 ssh-add 来管理私钥,如下是 ssh-add 的一些习惯用法:
- ssh-add filename:添加指定私钥,如 ssh-add ~/.ssh/id_rsa_gh 将 ~/.ssh/id_rsa_gh 添加到 ssh-agent 内存中
- ssh-add -l:列出加载的私钥指纹
- ssh-add -L:列出加载的私钥对应的公钥
- ssh-add -D:删除所有加载的私钥
- ssh-add -d filename:删除指定的私钥
macOS 系统是开机自动启动 ssh-agent,而 Linux 需要执行 eval $(ssh-agent -s) 来启动 ssh-agent。在启动 ssh-agent 后,执行 ssh-add ~/.ssh/id_rsa_gh 将新生成的私钥添加到 ssh-agent,然后执行 ssh -T git@github.com 测试私钥是否正确。
这里有个问题,前面说到 ssh-agent 将私钥保存在内存中,那么当机器重启后,这些私钥信息都将失效,需要把所有需要的私钥再加载一遍。如何解决这个问题呢?这里有两种方案:
-
每次执行 ssh-add filename 添加私钥时,都将操作命令保存到 ~/.zshrc 或 ~/.bashrc 等终端工具中。
-
使用 keychain 来管理私钥。使用
ssh-add -K filename
可将私钥添加到用户的 keychain 中。
- macOS 自带 keychain,若 ssh 未使用 keychain,尝试在 ~/.ssh/config 中添加 UseKeychain yes,如: Host github.com UseKeychain yes
- Linux 通过包管理器可安装 keychain。
使用 ssh-agent 还能实现 SSH 代理转发的功能,更多内容可参考 An Illustrated Guide to SSH Agent Forwarding 和 使用 SSH 代理转发,由于这些内容和本文关系不大,故此不赘述。
配置 ssh config
编辑 ~/.ssh/config,针对不同的仓库地址配置不同的 Host、HostName、User 和 IdentityFile,如下:
Host github.com
HostName github.com
User user_gh
IdentityFile ~/.ssh/id_rsa_gh
Host gitlab.com
HostName gitlab.com
User user_gl
IdentityFile ~/.ssh/id_rsa_gl
这样不同的仓库即使用不同的信息了。
修改仓库配置
这里还有个问题,如果 github.com 上两个仓库使用的用户信息不同该如何处理呢?假设一个用户是 user_gh,一个用户是 qileq,分别有各自的私钥。配置过程如下:
-
修改 ~/.ssh/config,添加 User qileq 相关的信息,如下:
Host github.com HostName github.com User user_gh IdentityFile ~/.ssh/id_rsa_gh
Host github-qileq.com HostName github.com User qileq IdentityFile ~/.ssh/id_rsa_qileq
Host gitlab.com HostName gitlab.com User user_gl IdentityFile ~/.ssh/id_rsa_gl
-
修改仓库的 git 信息,将仓库配置 url 中的 github.com 替换为 ssh config 中设置的 Host 值。 以 Java 教程 java-roam-guide 为例,可以使用如下两种方式来修改仓库地址:
- 执行命令 git remote set-url origin git@github-qileq.com:qileq/java-learning.git
- 将该仓库 .git/config 中的 url = git@github.com:qileq/java-learning.git 修改为 url = git@github-qileq.com:qileq/java-learning.git 修改完成后,执行 git remote -v 查看仓库地址是否正确。 注:这里的仓库设置为 git 协议,非 https 协议。
问题
Repository not found
在 push/pull 部分仓库的数据时,有如下报错:
ERROR: Repository not found.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
除了检查完仓库是否输入错误外,若有多个 ssh 账户,可以执行 ssh-add -l 确认下是否相应的私钥未加载到内存中。若未加载,通过 ssh-add 加载后再次 push/pull 重试。
可以看到 SSH 有一套强大而又复杂的规则体系,通过正确的设置能节省我们不少时间。笔者这里抛砖引玉,对多账号的设置进行了一个总结,若有不当之处,请多指正。
本文由 huzd 创作,采用 知识共享署名4.0 国际许可协议进行许可本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名最后编辑时间
为:
2023/07/31 14:29