Git 的 HTTPS 凭据和 SSH 密钥

摘要

走哪一种由远程地址决定

GitHub 从 2021 年 8 月起,HTTPS 的 git push、git pull 不再接受账号密码,密码栏要填 Personal Access Token。每次手动粘贴令牌太麻烦,所以要么把令牌交给凭据助手保存,要么改用 SSH 密钥。

1
git remote -v

地址是 https://github.com/... 时走凭据助手。地址是 git@github.com:... 时走 SSH 密钥,不读凭据助手。同一台机器上两种可以并存,每个仓库按自己的远程地址选择。

HTTPS:凭据助手

选择助手

--global 写入 ~/.gitconfig,这个用户的所有仓库都会使用。设置后执行一次 git pull,按提示填写用户名和令牌;之后由助手提供,不再提问。

1
2
3
4
5
6
7
8
# macOS,存入钥匙串
git config --global credential.helper osxkeychain

# Linux,需要先安装 libsecret
git config --global credential.helper /usr/lib/git-core/git-credential-libsecret

# 用户名填 GitHub 用户名,密码填令牌
git pull

Windows 安装 Git Credential Manager 后,通常已经自动配置好助手。

store 把凭据以明文写进 ~/.git-credentials,任何能读这个文件的人都能拿到令牌。只在个人机器上、并且清楚这个风险时使用。

1
2
3
4
git config --global credential.helper store

# 首次输入用户名与令牌,之后从文件读取
git pull

从 store 换成钥匙串

git config --global credential.helper osxkeychain 只改 ~/.gitconfig 里的 credential.helper。~/.git-credentials 不会被删除或清空。助手改成 osxkeychain 之后,Git 不再读这个明文文件,但里面的令牌还在磁盘上。确认钥匙串里已经能推送之后,再自己删掉 ~/.git-credentials。

已有仓库不用逐个重配。钥匙串按协议和主机名保存,默认不区分仓库路径。同一个 https://github.com 只在钥匙串里还没有这项时问一次,之后这个主机上的其他 HTTPS 仓库共用这一条。Git 不会把 ~/.git-credentials 里的旧记录搬进钥匙串。

查看已保存的账号

钥匙串和 ~/.git-credentials 都要看。git credential-osxkeychain 不能列出全部记录。打开「钥匙串访问」,搜索 github.com(或其他主机名)。每条的帐户是用户名,勾选「显示密码」才看得到令牌。

知道主机名时,可以先只看用户名。带 -g 的那条,以及 get、cat,会把令牌打在终端上。

1
2
3
4
5
6
7
8
# 只打印 github.com 这条的用户名
security find-internet-password -s github.com | grep '"acct"'

# -g 打印密码,系统可能弹出授权框
security find-internet-password -s github.com -g

# 输出里有 username 和 password
printf "protocol=https\nhost=github.com\n\n" | git credential-osxkeychain get

store 留下的文件还在时,一行一条,格式是 https://用户名:令牌@主机:

1
cat ~/.git-credentials

gh auth status 只列出 gh 登录的账号和存放位置,不打印令牌。

清掉旧凭据

没有提问就报 Authentication failed 时,钥匙串里多半已有旧的 github.com 条目。清掉后再操作一次,就会重新提问。这条只删除钥匙串里的对应项,不动 ~/.git-credentials。

1
printf "protocol=https\nhost=github.com\n\n" | git credential-osxkeychain erase

和 gh 的关系

以前执行过 gh auth setup-git 时,github.com 的 HTTPS 可能仍由 gh 提供凭据,钥匙串那一条不会被用到。在仓库里看实际生效的助手和它所在的文件:

1
git config --show-origin --get-regexp 'credential\..*helper'

SSH:密钥

生成密钥

推荐 ed25519,密钥短、速度快。生成的是 ~/.ssh/id_ed25519(私钥)和 ~/.ssh/id_ed25519.pub(公钥)。已有同名文件时,命令会询问是否覆盖;覆盖后,旧公钥对应的服务器都要重新添加。

1
2
# -C 只是备注,便于在服务器上辨认这把密钥,不必是邮箱
ssh-keygen -t ed25519 -C "your_label"

服务器只支持 RSA 时:

1
ssh-keygen -b 4096 -t rsa -C "your_label"

把公钥加到服务器

把 ~/.ssh/id_ed25519.pub 的整行复制到服务器的 SSH 公钥设置页。私钥 ~/.ssh/id_ed25519 留在本机,不要上传。

  • GitHub:头像 → Settings → SSH and GPG keys → New SSH key。

  • Coding:个人设置 → SSH 公钥。

  • Gitee:设置 → 安全设置 → SSH 公钥。

逐个测试。GitHub 成功时输出 Hi 用户名! You've successfully authenticated。

1
2
3
ssh -T git@github.com
ssh -T git@e.coding.net
ssh -T git@gitee.com

使用 SSH 地址

新克隆时使用 git@ 开头的地址:

1
git clone git@github.com:hanqunfeng/reactive-redis-cache-annotation-spring-boot-starter.git

已经用 HTTPS 克隆的仓库,改远程地址即可。这条写入该仓库的 .git/config。

1
2
git remote set-url origin git@github.com:用户名/仓库名.git
git remote -v

ssh -T 能打出用户名,只说明这把密钥被服务器接受。推送仍然失败时,先看 git remote -v 的地址是不是 git@ 开头,以及这个账号对仓库有没有写权限。