第一次把本地仓库往远端推,终端甩回来一句Permission denied (publickey),盯着屏幕半天不知道该改配置还是该换密钥——这一幕几乎每个刚接触 Git 的人都撞过。git 中的 SSH 密钥配置说到底就是解决一件很朴素的事:让远端服务器确认"推代码的人确实是账号本人",顺带让你不用每次输账号密码。它不是什么高深的安全工程,而是一套一次性配好、之后几年都不用再碰的基础设施。但恰恰因为"配一次管很久",很多人第一次配的时候抄了半截教程就跑了,结果后面遇到多账号、换电脑、公司内网封端口,全都要从头再排查一遍。
这篇内容我会把 SSH 密钥从"为什么需要"讲到"多套密钥怎么隔离",再到"报错时怎么一层层往下挖"。刚装完 Git 的新手可以照着做,手上有三四个仓库账号的老手也能在密钥隔离和排错那几节找到点不一样的东西。全程以实际命令和真实现象为准,不讲空泛的安全口号。
1. 为什么Git现在必须走SSH密钥这条路
1.1 密码验证被关停这件事比你想的严重
很多人对 SSH 密钥的印象还停留在"可选的安全加固",觉得用账号密码也能推代码,密钥只是更保险一点。这个认知在几年前还算成立,现在早就过期了。主流代码托管平台已经陆续关掉了对密码验证的支持,用账号密码走 HTTPS 推送会被直接拒绝,提示你改用个人访问令牌或者 SSH。也就是说,SSH 密钥从"更好的选择"变成了"必备路径"之一。
驱动这次变化的原因不复杂。账号密码有两个天然缺陷:一是可以被暴力尝试,服务器每天要挡掉海量的撞库请求;二是密码往往在多个网站重复使用,一个地方泄露就连带受害。公钥认证从机制上就绕开了这两个问题——服务器手里只有你的公钥,公钥本身不能用来登录别的地方,你的私钥从头到尾不出本机。这不是"更安全一点"的差别,是攻击面直接消失了一整块。
1.2 HTTPS加令牌和SSH到底该怎么选
既然密码走不通了,实际就剩两条路:HTTPS 配合个人访问令牌,或者直接用 SSH。两条路都能用,但适用场景有区别。
HTTPS 加令牌的优势在于穿透性好。它走的是标准的 443 端口,任何能让你正常上网的网络环境基本都能通,公司防火墙、酒店无线网、客户现场的网络都不太会拦。代价是需要管理令牌的生命周期,令牌有有效期,过期了要重新生成、重新配置;多个账号同时在用的时候,凭据管理器容易把身份记串,切账号时莫名其妙推到别人仓库去。
SSH 的优势是"配一次长期有效"。密钥没有默认过期时间(有些平台可以手动设),配好之后几年不用管;多账号隔离靠配置文件就能做得非常干净,谁是谁一目了然;推送时不需要联网去校验令牌有效性,握手速度也更快。它的问题集中在初始配置和网络穿透上——第一连接要确认指纹,有些受限网络会拦掉 22 端口,需要换个端口走。
1.3 一张表看清三种鉴权方式的差别
把三种方式放在一起对比,选型会清楚很多:
| 对比维度 | 账号密码(已淘汰) | HTTPS + 访问令牌 | SSH 密钥 |
|---|---|---|---|
| 是否需要手动输凭据 | 每次或靠缓存 | 令牌过期后需重配 | 一次配置长期免输 |
| 默认有效期 | 长期 | 通常有明确过期时间 | 无,可手动设置 |
| 多账号隔离难度 | 高,容易串号 | 中,依赖凭据管理器 | 低,靠 config 文件 |
| 受限网络穿透性 | 好 | 好(走 443) | 一般,22 端口可能被拦 |
| 换电脑成本 | 输密码即可 | 重新生成令牌 | 迁移或重新生成密钥 |
| 私钥/令牌泄露后果 | 严重 | 令牌有效期内可被利用 | 可撤销单个公钥 |
我自己的习惯是:主力开发机一律用 SSH,配置一次管到底;临时借用别人电脑或者在某些网络环境特别苛刻的场合,才临时用 HTTPS 加令牌顶一下。两套并存不冲突,反正远程地址一个仓库只能选一种,改git remote set-url就能切换。
2. 密钥对到底是什么:私钥、公钥与known_hosts的分工
2.1 公钥私钥的非对称关系用一个比喻讲透
ssh-keygen执行完,.ssh目录下会多出两个文件,比如id_ed25519和id_ed25519.pub。新手最容易搞混的就是这两个文件谁该给谁。
可以用一把门锁来理解:公钥是锁芯,你可以把它复制无数份,钉在任何一扇门上,发给任何人都无所谓;私钥是唯一能开这把锁的钥匙,只能留在你自己手里。注册流程是:你把自己的"锁芯"交给代码托管平台,平台把它装到你的账号上;之后你每次连接,平台就用这把锁考验你,只有你的钥匙能通过。整个过程你的钥匙从来没有离开过本机,网络上传输的只是"我用钥匙开了一次锁"的证明。
所以有一条铁律:永远只把.pub结尾的文件内容贴到平台上。如果你把没有.pub的那个文件内容贴上去,平台会提示密钥格式无效,一般拦得住;但如果你把私钥内容当成"备份"发给了别人、贴进了聊天记录或者提交到了仓库,那就等于把钥匙配了一份给全世界,必须立刻在平台上删掉对应公钥并重新生成一对。
2.2 known_hosts记录的不是你的密钥
~/.ssh/known_hosts这个文件经常被误解成"保存账号信息的地方",其实它记录的是服务器自己的公钥指纹,和你的身份没有任何关系。
它的作用是防中间人。你第一次连接某个服务器时,SSH 客户端没法判断对面是真正的服务器还是伪造的,所以会弹出一句The authenticity of host 'github.com' can't be established,然后给你一串指纹让你确认。你输入yes之后,这个指纹就被写进known_hosts。以后每次连接,客户端都会拿服务器出示的指纹和记录比对,对不上就会报WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED并拒绝连接。
这个警告是真的要当回事。它可能意味着服务器换了密钥(运维正常变更,重新确认一次即可),也可能意味着有人在中间冒充服务器。绝大多数情况是前者,但处理动作不能是"把整行删掉眼不见为净"——正确做法是核对平台官方公布的最新指纹,确认一致之后再更新记录。
2.3 ssh-agent在中间扮演什么角色
如果你给私钥设置了密码短语(passphrase),那每次 Git 操作都要输一遍,用起来会很烦。ssh-agent就是来解决这个烦的。
它是个常驻后台的小进程,你把私钥通过ssh-add交给它,它在内存里保存一份解密后的副本。之后 SSH 客户端需要签名时,就找 agent 要,不用再问你。对使用者来说,效果就是"开机输一次密码短语,一整天都不用再输"。
三个常用命令值得记一下:
# 查看 agent 当前加载了哪些密钥(-l 显示指纹) ssh-add -l # 加载指定私钥 ssh-add ~/.ssh/id_ed25519 # 清空 agent 里所有密钥(排查多账号串号时很好用) ssh-add -D在 macOS 上,系统钥匙串可以直接托管密码短语,配置之后连"开机输一次"都省了。在 Windows 上,如果用 Git 自带的 OpenSSH,agent 通常随 Git Bash 会话自动启动;如果用的是系统自带的 OpenSSH 服务,需要在服务管理器里把OpenSSH Authentication Agent设为自动并启动。这一点后面排错那节还会提到,因为它是一个高频的坑。
3. 用ssh-keygen生成密钥时,那几个参数到底怎么选
3.1 算法选ed25519还是RSA
ssh-keygen -t后面跟的就是算法类型。现在默认推荐ed25519:
ssh-keygen -t ed25519 -C "your_email@example.com"ed25519 的优势是密钥短、生成快、签名验证快,同等安全强度下的密钥长度远小于 RSA。它的兼容性问题主要出在"非常老的设备"上——某些出厂年份较早的服务器、老版本的内网设备可能还不支持它。如果你连的是这类环境,退回 RSA 并加长密钥长度更稳妥:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"这里的-b 4096只在 RSA、DSA 这类算法下有意义,它指定密钥位数,位数越大越难破解、签名计算也越慢。给 ed25519 加-b是无效的,它本身是固定长度的曲线算法,参数会被忽略。至于更老的 DSA、ECDSA,现在没必要主动选,前者已被主流平台弃用,后者在某些实现上有过争议参数问题,直接用 ed25519 或 RSA 4096 就够了。
3.2 -f、-C、-b参数的实际影响
-f是输出文件路径。这一步很关键:如果你不指定,默认会写到~/.ssh/id_ed25519,而这个文件可能已经存在了。第二次生成时它会问你要不要覆盖,很多人没细看直接回车,结果把原来能用的密钥覆盖掉了,之前挂到平台上的公钥全部失效。
多账号必须用-f指定不同的文件名,比如:
ssh-keygen -t ed25519 -C "work@company.com" -f ~/.ssh/id_ed25519_work ssh-keygen -t ed25519 -C "personal@example.com" -f ~/.ssh/id_ed25519_personal-C是注释,会附加在公钥末尾。默认值是当前用户@主机名,信息量很低——过半年你回过头看平台上挂着三把user@MacBook-Pro,根本分不清哪把是哪个用途。建议在生成时就写成"邮箱 + 用途",比如work@company.com-gitlab,这样在平台的密钥列表里一眼能认出来。
-b前面说过了,只管 RSA 系列的位数。还有一个容易被忽略的参数是-t后面的算法名,如果打错了,ssh-keygen会直接报错退出,不会生成半个文件,这一点上它比很多工具让人安心。
3.3 passphrase要不要设
密码短语是私钥文件本身的加密口令。私钥文件躺在硬盘上,谁拿到这个文件谁就能冒充你。设了密码短语之后,即使文件被拷走,对方也需要额外破解这个口令才能使用。
有争议的地方在于"设了太麻烦"。这个顾虑在 agent 出现之后基本不成立了:设一个强度足够的短语,交给 agent 或系统钥匙串缓存,日常体验和不设没区别。我的建议是,工作机、经常携带外出的笔记本一定要设;纯粹家里固定摆着、不接外人的机器可以权衡,但设了肯定不吃亏。
如果确实不设,直接一路回车跳过即可,生成时会提示no passphrase。想修改已有密钥的密码短语,用:
ssh-keygen -p -f ~/.ssh/id_ed255193.4 Windows和macOS上的路径差异
密钥默认存放在用户主目录下的.ssh文件夹。这个文件夹在 Windows 上是隐藏的,路径是C:\Users\你的用户名\.ssh;在 Git Bash 里则显示为/c/Users/你的用户名/.ssh。macOS 和 Linux 下就是~/.ssh。
生成完之后,权限也要顺手检查一遍。SSH 客户端对权限非常敏感,私钥文件权限过宽会直接拒绝使用。在 macOS 和 Linux 上:
chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 chmod 644 ~/.ssh/id_ed25519.pub chmod 600 ~/.ssh/configWindows 上的权限模型不一样,没有chmod这个概念。如果客户端报Permissions 0644 for 'xxx' are too open,需要用图形界面或icacls把.ssh文件夹的继承权限关掉,只保留当前用户。具体操作在排错那一节展开。
4. 把公钥挂到GitHub、GitLab、Gitee上的具体操作
4.1 三个平台入口位置对照
平台不同,粘贴公钥的入口位置也不同,但逻辑完全一致:都在个人设置里找一个"SSH 密钥"的入口。
| 平台 | 入口路径 | 特别说明 |
|---|---|---|
| GitHub | Settings → SSH and GPG keys → New SSH key | 类型选 Authentication Key,签名用的要分开 |
| GitLab | Preferences → SSH Keys | 支持设置过期日期,到期需重新添加 |
| Gitee | 设置 → SSH 公钥 | 支持添加部署公钥,只读权限 |
GitLab 的过期时间设置值得留意。它默认可以勾选一个有效期,到期后这把密钥自动失效,推送就会突然失败。如果你在 GitLab 上遇到"昨天还能推、今天就不行"的情况,先去密钥列表看一眼是不是过期了。GitHub 现在也提供了密钥的到期提醒机制,但不会自动禁用,只是邮件提示。
4.2 复制公钥时最容易犯的错
公钥文件的内容是长长的一行,以算法名开头,中间是 base64 编码的密钥数据,末尾是-C指定的注释。复制时常见两类错误:
第一类是复制不全或带上了多余内容。用cat打印出来手动框选很容易漏掉中间某一段,或者把终端里的换行符也一起复制进去。推荐的复制方式是按系统来:
# macOS pbcopy < ~/.ssh/id_ed25519.pub # Windows(Git Bash 中) cat ~/.ssh/id_ed25519.pub | clip # Linux(需要 xclip) xclip -sel clip < ~/.ssh/id_ed25519.pub这样保证拿到的是文件完整内容,不多不少。
第二类是复制错了文件。id_ed25519和id_ed25519.pub在文件列表里紧挨着,手快就容易点错。判断方法很简单:.pub文件很短,就那么一行;私钥文件长得多,开头是-----BEGIN OPENSSH PRIVATE KEY-----,中间是一大段多行内容,末尾是-----END OPENSSH PRIVATE KEY-----。如果你复制到的是后一种格式,说明拿错了,赶紧关掉粘贴框。
4.3 用ssh -T验证首次连接
公钥贴上去之后,不要急着git clone,先用测试命令确认链路通了:
ssh -T git@github.com注意这里的用户名固定是git,不是你的账号名。这是所有代码托管平台的约定,服务器靠公钥来识别你是谁,用户名只是一个占位。GitLab 和 Gitee 同样如此。
连接成功时的返回大致是这样:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.看到successfully authenticated并且带上了你的用户名,就说明密钥配对成功了,剩下的does not provide shell access只是平台告诉你"这里不提供登录终端",不影响使用。GitLab 会返回Welcome to GitLab, @username!,Gitee 的返回格式类似。
4.4 首次连接的指纹确认
第一次执行测试命令时,会看到这样一段提示:
The authenticity of host 'github.com (x.x.x.x)' can't be established. ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxx. Are you sure you want to continue connecting (yes/no/[fingerprint])?这里必须输入完整的yes,不能只敲回车或y(部分新版本 SSH 支持直接粘贴指纹)。敲完之后这段记录会写进known_hosts,下次就不再问了。
有个细节值得提醒:这段指纹最好和平台官方文档公布的指纹核对一次。虽然被中间人劫持的概率不高,但既然客户端主动把这个确认环节留给你,随手比一下成本极低。确认过一次之后,同一个服务器就不会再问。
5. 一台机器管理多套密钥:config文件才是主战场
5.1 为什么多账号会互相打架
当.ssh目录里躺着两把以上密钥时,SSH 客户端的默认行为是按固定顺序去尝试:先看配置里指定的,没指定就按id_rsa、id_ecdsa、id_ed25519这类默认名依次试。它不会"区分场景",只会一把一把往服务器递,谁先被接受就用谁。
结果就是:你明明想用工作账号推代码,客户端却先把个人密钥递了上去。如果个人密钥恰好也被这个平台的其他账号接受过(比如同一个平台的第二个账号),那就推错人了。更隐蔽的情况是,服务器只接受其中一把,客户端试了四五把才试对,每次连接都慢一截,你还以为是网络问题。
要解决这个问题,靠文件名区分是不够的,必须在~/.ssh/config里明确告诉客户端:连这个主机用哪把钥匙,而且只用这一把。
5.2 config文件的字段逐行拆解
~/.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逐行解释一下,因为这几行的作用经常被弄混:
Host:这是你自己起的一个别名,之后在 Git 远程地址里用的就是它。它不需要是真实存在的域名,叫github-work还是gh-w都行,只要别和真实域名冲突。HostName:真实要连接的主机地址,这里必须写准确的域名。User:登录用户名,代码托管平台统一是git。IdentityFile:指定使用哪把私钥。IdentitiesOnly yes:这个是最关键的一行。它强制客户端只使用配置里指定的密钥,不去尝试 agent 里的其他密钥,也不去按默认名依次试。少了这行,前面辛苦做的隔离可能全白费。
如果.ssh目录里的密钥文件名不满足默认命名规则(也就是不叫id_rsa那套),还可以在文件开头加一段全局声明:
Host * AddKeysToAgent yes ServerAliveInterval 60AddKeysToAgent yes让密钥在首次使用时自动加入 agent;ServerAliveInterval 60每 60 秒发一次保活包,防止长时间空闲的推送连接被中间设备掐断。这两个属于可选优化,不影响基本功能。
5.3 远程地址要不要改
配置写完之后,还要改仓库的远程地址,让它指向你定义的别名。新建仓库时:
git clone git@github-work:your-org/your-repo.git已有的仓库改地址:
git remote -v # 先看看现在指向哪里 git remote set-url origin git@github-work:your-org/your-repo.git注意别名后面跟的是冒号,不是斜杠,整体格式是git@别名:组织名/仓库名.git。这是最容易写错的地方,写成git@github-work/your-org/your-repo.git一定会报仓库不存在。
如果某个仓库只想临时用另一把密钥,不想改动全局配置,可以用-c参数指定:
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ed25519_temp" git clone git@github.com:org/repo.git这种方式适合"就这一次"的场景,用完就忘,不污染配置文件。
5.4 顺带解决提交人身份问题
SSH 密钥决定的是"你以什么身份连接服务器",和"提交记录里写谁的名字"是两件独立的事。多账号场景下这两件事都得配对,否则会出现"代码推到了工作仓库、提交记录却写着个人邮箱"这种尴尬。
Git 支持按目录自动切换提交身份,靠的是includeIf:
# ~/.gitconfig [user] name = Your Name email = personal@example.com [includeIf "gitdir:~/work/"] path = ~/.gitconfig-work然后在~/.gitconfig-work里写:
[user] name = Your Work Name email = work@company.com这样只要仓库路径位于~/work/目录下,Git 就自动使用工作身份提交,其他目录继续用个人身份。注意路径末尾的斜杠不能省,它表示"这个目录及其子目录"。这套机制配合前面的 SSH 别名,才算把多账号场景真正理顺。
6. 连不上时的完整排查链路:从报错到根因
6.1 Permission denied (publickey) 的六种成因
这个报错是 SSH 相关的头号高频问题,但它的成因至少有六种,报错文字完全一样,处理方式却各不相同。列出我实际遇到过的:
| 成因 | 判断线索 | 处理方式 |
|---|---|---|
| 公钥没上传或上传失败 | 平台密钥列表里没有这把 | 重新粘贴.pub内容 |
| 复制时内容不完整 | 平台提示密钥格式无效 | 用 clip/pbcopy 重新复制 |
| 私钥没被加载 | ssh-add -l里看不到 | ssh-add手动加载 |
| config 里主机写错 | ssh -vT里 Host 不匹配 | 检查 HostName 拼写 |
| 密钥权限过宽 | 提示 Permissions are too open | chmod 600 或改 ACL |
| 平台侧密钥被删或过期 | 列表里找不到或已标灰 | 重新添加或延期 |
排查顺序建议从"平台侧有没有这把公钥"开始往本地查,因为这一步最容易被忽略。很多人反复在本地折腾配置,最后发现是当初粘贴时格式没对,平台压根没保存成功。
6.2 用ssh -vT把握手过程摊开看
-T是禁止分配终端,-v是输出详细过程,两个一起用能看到完整的握手链路:
ssh -vT git@github.com输出会很长,但我们只关心两类行:debug1: Offering public key:和debug1: Authentications that can continue:。前者告诉你客户端把哪把钥匙递了出去,后者告诉你服务器还在等什么样的认证。如果Offering后面跟的路径不是你预期的那个,说明 config 或 agent 里有多余的密钥在抢。
把-v换成-vvv能看到更细的加密协商过程,一般在怀疑算法不兼容时才需要。日常排错用一层-v足够。
还有一个容易被误判的现象:如果Offering显示的确实是正确的密钥,但依然被拒,那基本可以确定问题在服务端——公钥没保存、保存错了、或者被禁用了。这时候就别在本地继续折腾了。
6.3 known_hosts冲突与密钥权限过宽
这两类报错的特征文字都很有辨识度,看到了可以直接对症下药。
第一种,服务器指纹变了:
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!先别慌,去平台官方文档核对当前指纹,确认一致后删掉旧记录重连:
ssh-keygen -R github.com这个命令会把known_hosts里和该主机相关的行标记为注释删除,比手动编辑安全。删完再连一次,重新确认新指纹即可。
第二种,私钥权限过宽:
Permissions 0644 for '/Users/xxx/.ssh/id_ed25519' are too open.macOS 和 Linux 上chmod 600解决。Windows 上的处理稍麻烦一些,需要用icacls或者图形界面把.ssh目录的继承权限关掉:
icacls "C:\Users\你的用户名\.ssh" /inheritance:r icacls "C:\Users\你的用户名\.ssh" /grant:r "%USERNAME%:R"也可以走图形界面:右键.ssh文件夹 → 属性 → 安全 → 高级 → 禁用继承 → 删除继承的权限,只保留当前用户。这一步做完,私钥文件的其他用户权限就没了,客户端不会再报权限警告。
6.4 22端口不通时的备用方案
有些公司内网、校园网或者公共网络环境会限制出站的 22 端口,表现是连接超时而不是拒绝。判断方法是用-v看输出,如果卡在Connecting to github.com port 22之后就没了下文,基本可以判定端口被拦。
这时候可以让 SSH 走 443 端口。以 GitHub 为例,平台提供了一个专用的域名来承接这种连接:
Host github.com HostName ssh.github.com Port 443 User git加进~/.ssh/config之后再执行一次ssh -T git@github.com,会提示你确认[ssh.github.com]:443的指纹,输yes即可。GitLab 和 Gitee 也有类似的备用入口,具体域名可以查平台的官方帮助文档。
需要说明的是,这种做法只是换了一条合法可用的连接通道,前提是你所处的网络环境允许访问 443 端口,不存在绕过任何管控的意图。如果 443 也不通,那就只能临时改用 HTTPS 加令牌的方式推代码,等离开该网络环境再切回 SSH。
7. 密钥的长期维护:几件容易被忽略的小事
7.1 私钥绝对不能进仓库
这条说起来像废话,但每年都有真实的泄露事故,而且往往发生在"不小心"的情况下。最常见的是初始化仓库时手滑git add .,把某个临时放进去的密钥文件一起提交了;或者把密钥导出到项目目录里"临时用一下",结果忘了删。
防御手段有两层。第一层是在全局.gitignore里预先屏蔽:
# ~/.gitignore_global *.pem *.key id_rsa id_rsa.pub id_ed25519 id_ed25519.pub然后让 Git 引用这个全局忽略文件:
git config --global core.excludesfile ~/.gitignore_global第二层是在推送前用git status多看一眼新增了什么文件,尤其是第一次推新仓库的时候。已经误提交的,光删除文件是不够的,历史记录里还留着,需要用git filter-repo之类的工具重写历史,同时立刻去平台撤销对应的公钥并重新生成一对——因为一旦私钥泄露,撤销才是唯一有效的止损方式。
7.2 定期轮换与撤销
密钥不是配好就一劳永逸的东西。换电脑、换岗位、怀疑某台设备不安全了,都应该把对应的公钥从平台上删掉。GitLab 支持给密钥设置过期时间,可以顺手加上;GitHub 会定期提醒长期未更换的密钥,提示邮件别当垃圾邮件删掉。
查看本地密钥的指纹,用来和平台上显示的指纹做比对:
ssh-keygen -lf ~/.ssh/id_ed25519.pub输出的格式类似256 SHA256:xxxxxxx comment (ED25519)。平台密钥列表里通常也会显示指纹,两边一致说明挂上去的确实是你以为的那把。这个比对在"明明有两把密钥却怎么都连不上"的场景下特别有用,能快速确认是不是挂错了。
换机器时的迁移方案有两种:把加密后的私钥文件安全地搬到新机器(不要用聊天软件传),或者干脆在新机器上重新生成一对、把旧的删掉。后者更干净,我一般推荐后者,除非有特别的原因必须保留原密钥。
7.3 在编辑器里使用同一套密钥
现在很多人是直接在 VS Code 这类编辑器里写代码、点按钮提交,底层调用的还是系统里的git命令,所以只要命令行里通了,编辑器里一般也通。真正会出问题的是 Windows 上装了多个 SSH 客户端的情况:Git 自带一套 OpenSSH,Windows 系统也自带一套,装了 WSL 还有一套。编辑器里内置的终端到底调用了哪一套,取决于环境变量PATH里的顺序。
判断当前用的是哪套:
which ssh ssh -V如果发现编辑器里连不上但 Git Bash 里正常,大概率是两边的 SSH 客户端不是同一个,读的配置文件、加载的 agent 也不同。解决办法是把 PATH 里想要的那套提前,或者统一用同一套——我个人习惯是让 Git 自带的 OpenSSH 优先,因为它和 Git 自身的集成最省心。
另外一个常见现象是编辑器的 Git 面板提示"未检测到仓库"或者一直转圈,这时候别怀疑密钥,先看仓库根目录有没有.git文件夹。密钥问题只会导致推送拉取失败,不会导致仓库识别不出来,把这两类问题分清楚能省下不少排查时间。
这套东西配好之后,日常使用其实完全感觉不到它的存在——克隆、拉取、推送一路顺畅,只有在换机器或者处理多账号的时候才会想起来它。我个人在实际操作中的体会是,把config文件按用途一块块写清楚、注释写足,比事后翻着报错反推要省事得多;而遇到连不上的时候,先跑一遍ssh -vT,看客户端到底递出了哪把钥匙,绝大多数问题在这一步就能定位到方向。