说实话,在Windows上用Git,最劝退的开销不是命令记不住,而是隔三差五就要被密码锤一遍。尤其现在的代码托管平台普遍不再支持账号密码直连Git,HTTPS方式让你输的都是Personal Access Token,一串英文数字比Wi-Fi密码还容易忘。今天我把这套Windows + Git + ssh-agent的配置方式完整写清楚,帮的是每天要push、pull、clone的开发者,也包括同时折腾GitHub、Gitee、公司GitLab的“多平台选手”。看完你会知道为什么SSH密钥比密码靠谱,也知道怎么让ssh-agent这个“钥匙保管员”全程不离职,从此跟git密码说拜拜。
1. 先理清思路:HTTPS也好SSH也好,密码到底卡在哪
1.1 密码和Token都是临时凭证,密钥才是长期身份
绝大多数人最初用Git,remote地址都是HTTPS,也就是https://github.com/用户名/仓库.git这种。走HTTPS协议时,服务器要验证“你是谁”,于是Git就向你要凭证:早期要账号密码,后来GitHub这类平台干脆禁止账号密码,改成Personal Access Token。Token本质上就是一个带权限的临时密码,问题是它本身就有有效期,你还要去网页后台重新生成、复制、粘贴,整个过程非常反人类。
而切换到SSH协议后,远程地址长这样:git@github.com:用户名/仓库.git。SSH走的是公钥加密体系,不再需要账密,也不用保存Token。你本地持有一把私钥,服务器上登记一把公钥,连接时只要私钥能对上公钥,身份就算验证通过。所以配置好之后,整个Git操作流程不再弹出任何密码提示,不是你“记住了密码”,而是压根不需要密码了。
1.2 公钥、私钥、passphrase分别是什么
把SSH密钥想成一把门锁和一把钥匙。公钥是锁头,安装在代码托管平台的服务器上,任何人都能看到,但锁头本身打不开门。私钥是钥匙,保存在你本地,基本上就是~/.ssh下那个文件,它才是真正证明你身份的东西,绝不能泄露。
私钥文件本身还能设置一道口令,术语叫passphrase。你可以把passphrase理解为“钥匙套了一层保险膜”,每次拿这把私钥去跟服务器打招呼时,都要先输入这个口令。好处是即使密钥文件被拷走了,没有passphrase也白搭;坏处是每次操作都要输一次,而这个“每次”就是Git体验的堵点。
1.3 ssh-agent就是帮你长期保管“已解锁钥匙”的管家
ssh-agent就是来解决这个堵点的。它是一个驻留在系统后台的代理进程,做的活儿很简单:你把私钥交给它,它把私钥读进内存并保持解锁状态,之后任何程序(包括Git)需要私钥做身份验证时,只要向它发一个签名请求,它就用内存里那把已经解锁的私钥完成签名,然后把结果返回给程序。全程不暴露私钥内容,也再不需要你在每一次push时重复输入passphrase。
你在一个终端窗口里敲一次ssh-add把钥匙交给agent,接下来这个系统里所有git操作都走同一个agent,不用每个项目配置一遍,也不需要反复输入口令。这才是标题说的“再也不用输入git密码”的真正原理:不是密码消失了,而是ssh-agent替你保管并使用了它。
1.4 别为了省事把passphrase去掉
网上有不少教程会让你生成密钥时直接回车、不设passphrase,理由是“反正ssh-agent会帮我保管”。我劝你别这么干。私钥文件一旦落地,如果二进制内容被人拷走,没有passphrase就是门洞大开;有passphrase好歹还能争取时间撤回登记、重新生成。ssh-agent设计的初衷就是让你“既能设passphrase,又不用每次输入”,所以请不要为了让agent计划少一步而放弃这层保护。个人开发机设一个方便记忆但别太短的口令即可,一整天只需要输一次,这个成本完全能接受。
2. Windows环境准备:Git、OpenSSH、密钥三件套
2.1 安装Git for Windows并验证
这一步看起来基础,但版本影响后续很多行为。Git for Windows官网下载安装包,或者直接走winget一行搞定:
winget install --id Git.Git -e --source winget装完不要急着关终端窗口,先验证一下:
git --version只要正常输出版本号就说明Git已经进入PATH。如果提示找不到命令,大概率是安装时“Adjusting your PATH environment”那一步没选对,重新安装并确保选中“Git from the command line and also from 3rd-party software”。
2.2 确认Windows自带OpenSSH并补齐组件
Windows 10 1803之后的系统默认带OpenSSH客户端,但各机器情况不一样,最好主动确认一遍。在PowerShell里执行:
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*'如果状态是Installed,直接往下走。如果是Not Present,执行安装命令:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0这里容易被忽略的坑:Windows系统自己的OpenSSH和Git for Windows捆绑的OpenSSH是两套东西,后面配置agent时会遇到。这里先把系统组件弄好,它就是我们要用的那套“标准件”。
2.3 生成自己的SSH密钥对
打开PowerShell,先确保~/.ssh目录存在,然后生成密钥:
if (-not (Test-Path "$HOME\.ssh")) { New-Item -ItemType Directory -Path "$HOME\.ssh" | Out-Null } ssh-keygen -t ed25519 -C "你的备注,通常写邮箱" -f "$HOME\.ssh\id_ed25519"参数单独说一下:
-t ed25519:指定算法。ed25519密钥更短、生成速度快、安全性不输RSA 4096,现在主流的托管平台都支持。-C:注释信息,方便你在平台后台区分不同电脑的密钥,填自己的邮箱或者设备名都行。-f:指定保存路径,我习惯放在~/.ssh/id_ed25519。
执行后会提示“Enter passphrase”。这里建议输入一个口令,哪怕简单一点,也比空着强。同一个口令之后要输入多少回?就一次,因为下一步的agent会一直帮你记着。
2.4 把公钥上传到GitHub、Gitee等平台
公钥文件是id_ed25519.pub,注意是带.pub后缀的那个,千万别把私钥内容贴上去。复制公钥在PowerShell里执行:
Get-Content "$HOME\.ssh\id_ed25519.pub" | Set-Clipboard然后到平台后台的“SSH keys”页面新增。GitHub是Settings -> SSH and GPG keys -> New SSH key,Gitee是设置 -> SSH公钥,GitLab一般是Preferences -> SSH Keys。把剪贴板里的内容整段粘贴进去,保存时如果提示需要确认密码,输入平台登录密码即可。
注意:上传公钥这一步不能省,
ssh -T后面所有验证失败,第一怀疑对象就是公钥没传或者传错了。
3. 让ssh-agent跑起来并接管密钥,才是免密的临门一脚
3.1 把Windows的ssh-agent服务设为自动启动并手动拉起
Windows自带的OpenSSH包含一个ssh-agent服务,服务名就叫ssh-agent。这个服务默认是手动启动状态,所以你要先把它改成自动,并立即启动。
以管理员身份打开PowerShell,依次执行:
Set-Service -Name ssh-agent -StartupType Automatic Start-Service ssh-agent Get-Service ssh-agent第三条命令用来确认状态,结果里Status应该是Running,StartType是Automatic。这一步做完,ssh-agent就常驻系统了,不需要每次开机手动去启动它。
如果你不习惯命令行,也可以按Win + R输入services.msc回车,找到“OpenSSH Authentication Agent”,右键属性,启动类型选“自动”,然后点“启动”。效果一样,随你习惯。
3.2 统一SSH客户端,避免“两套ssh打架”
这是Windows环境最隐蔽的坑。Git for Windows在安装时会自带一套OpenSSH,而Windows系统组件里还有另一套OpenSSH,两套工具默认情况下互不买账。现象就是:你明明在PowerShell里把私钥加到了系统ssh-agent里,git push偏偏还是提示认证失败,因为Git调用的是它自己捆绑的ssh.exe,它根本不知道系统agent里存了什么。
解决办法就是让Git也用系统那一套OpenSSH,通过一个配置项指定:
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"设置完可以用git config --global --get core.sshCommand确认。这一步之后,Git在执行SSH协议操作时,会直接调用系统的ssh.exe,从而和Windows的ssh-agent服务对接。前面的服务配置才真正生效。
如果你之前照着某些教程在~/.bashrc里写过eval "$(ssh-agent -s)",建议把那段删掉或注释掉。那种方式是Git Bash用户态的agent,只会跟着终端窗口存活,关一个窗口就丢一次密钥,和系统服务是两套东西,留着只会添乱。
3.3 用ssh-add把私钥交给agent并验证
现在把私钥添加到agent里:
ssh-add "$HOME\.ssh\id_ed25519"如果设置了passphrase,这里会提示输入一次,正确输入后这条命令没有任何多余提示就结束了,然后你可以用下面的命令查看agent现在管着几把钥匙:
ssh-add -l正常会输出一行指纹信息,例如256 SHA256:xxxxxx ... (ED25519)。如果提示“The agent has no identities”,说明key没加入成功,回到上一步检查路径和passphrase。
这一步是整个方案的“临门一脚”,做对了,后面所有git操作都不会再问你密码。
3.4 测试和GitHub、Gitee等平台连通性
不要急着去clone仓库,先用下面命令测试能否通过SSH认证:
ssh -T git@github.com首次连接时SSH会提示你确认服务器指纹,输入yes回车即可。之后如果你看到类似:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.说明一切正常。Gitee则执行:
ssh -T git@gitee.com看到“Hi 用户名! You've successfully authenticated, but GITEE.COM does not provide shell access.”就是成功。如果你在公司GitLab,则换成对应域名,例如ssh -T git@gitlab.example.com。
3.5 把现有仓库远程地址切到SSH
上面的步骤解决的是“以后新操作怎么办”,但电脑上已经存在的仓库,remote地址很可能还是HTTPS,需要手动切换。先看当前远程地址:
git remote -v输出一般是:
origin https://github.com/username/repo.git (fetch) origin https://github.com/username/repo.git (push)只要开头还是https://,就执行:
git remote set-url origin git@github.com:username/repo.git这里把username和repo换成实际的用户名和仓库名。改完再用git remote -v确认,然后随便试一次git fetch,你会发现终端安静得让人感动。
以后新clone仓库也统一用SSH格式,例如git clone git@github.com:username/repo.git,从源头避开密码环节。
4. 实战常见问题与排查技巧实录
4.1 “Could not open a connection to your authentication agent”怎么破
这句话我见过太多人问了,基本发生在执行ssh-add的时候,意思是当前系统里根本找不到一个可用的agent进程。原因就两类:一是本章第3.1步的ssh-agent服务没启动,二是你当前终端用的是旧版Windows自带的OpenSSH,还没有agent服务。前者用Get-Service ssh-agent查状态,后者需要先确认Windows版本并更新OpenSSH组件。还有一个场景是在Git Bash里执行导致,Git Bash默认环境变量和系统服务对不上,建议统一用PowerShell来操作。
4.2 “Permission denied (publickey)”的排查清单
这个报错信息非常笼统,但原因基本可以按下面顺序排查:
| 排查顺序 | 检查项 | 怎么查 |
|---|---|---|
| 1 | 公钥是否上传 | 去平台SSH keys页面看有没有对应的公钥 |
| 2 | 私钥是否添加到agent | ssh-add -l看有无指纹 |
| 3 | remote地址是不是SSH格式 | git remote -v,开头必须是git@或ssh:// |
| 4 | 用户名是否写对 | git remote -v里的username对应你的账号或组织名 |
| 5 | 是否多个key指向错误 | 检查~/.ssh/config的IdentityFile配置 |
其中第五类问题最隐蔽。如果你电脑上有多个密钥文件,SSH默认会按id_ed25519、id_rsa这样的文件名顺序尝试,一旦顺序不对就会拿A账号的钥匙去开B账号的门锁。解决办法就是写一个~/.ssh/config,把不同域名的密钥绑定给给不同Host:
Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/gitee_ed25519 IdentitiesOnly yesIdentitiesOnly yes这句的意思是“只允许用我指定的这把钥匙”,不加这句,系统还是会挨个试所有agent里的key,遇到多个key时依然可能混乱。
4.3 为什么重启电脑之后又要重新ssh-add
Windows的ssh-agent服务设了自动启动,这个服务本身会开机自启,但agent内存里的密钥列表并不会自动恢复,所以每次开机后你需要执行一次ssh-add,输入一次passphrase,之后一整天都清爽。如果你连每天这一次都不想输,那就只能在生成密钥时不设passphrase,同时确保私钥文件只有自己账户可读,这个方案我建议仅限个人独立开发机。
更安全又省心的折中方案是把ssh-add "$HOME\.ssh\id_ed25519"写成一个简单脚本,登录后双击运行,虽然还是要输一次口令,但至少不用记命令。我个人是接受“每天一次口令”的交互成本,换来的是私钥文件泄露也无法被直接使用。
4.4 22端口连不上的场景
有些办公网络或安全策略会屏蔽默认的22端口,表现是ssh -T git@github.com执行后一直卡住不动,最终超时。这个过程中其他步骤都没问题,公钥也上传了,agent也正常。此时优先确认是不是端口问题:换个网络环境再试一次,或者用Test-NetConnection github.com -Port 22看看22端口是否可达。如果确实是端口被限制,可以考虑在~/.ssh/config里给对应Host加上Port 443(前提是托管平台支持SSH over 443),或者干脆这个环境用HTTPS + token方式,不用硬刚。
4.5 检查私钥文件权限,避免“开放权限”警告
Windows的OpenSSH对手key文件的权限很敏感,如果私钥文件权限范围过宽,SSH会直接拒绝使用,并在ssh -T时给出“UNPROTECTED PRIVATE KEY FILE”之类的提示。解决办法是右键私钥文件,进入“属性 -> 安全”,把除了当前用户外的其他账户移除,只保留SYSTEM和当前用户。命令行也可以快速收敛权限,但图形界面最直观。这个问题常见于你从别处拷贝密钥文件过来,或者用压缩包解压后没处理权限。
5. 几个我实际用下来的习惯,少走弯路
现在我个人在Windows上的固定操作流程是这样:开机后打开PowerShell,执行一次ssh-add "$HOME\.ssh\id_ed25519",输入passphrase,然后这一整天的push、pull、fetch全部都不再碰密码。新项目一律用git clone git@github.com:...这种SSH地址拉取,老项目也陆续把remote切了过来。说实话,刚开始适应SSH地址的时候会觉得不如HTTPS直观,但习惯了就回不去了,因为没有任何凭证过期、Token失效这些幺蛾子。
还有一个容易踩的小坑:如果你用的不是PowerShell而是纯cmd,部分命令写法不同,比如Get-Content之类在cmd里不存在,所以文中演示基本都是PowerShell命令,这也是推荐工作环境。Git Bash能用,但要格外注意它自己那套ssh,建议用我前面说的core.sshCommand统一指向系统OpenSSH,否则会出现“明明在Git Bash里能用,在VS Code终端里又抽风”的诡异现象。
把ssh-agent这一套配好后,Git的使用体验才算是真正“现代化”。以后再有人抱怨Windows上Git难用,大概率是没跨过今天这篇文档里的某一个环节——要么agent服务没启动,要么公钥没上传,要么两套ssh在打架。按这个流程走一遍,你就能体会那种“终端全程安静”的快乐。