解决 Windows 环境下 Git SSH Permission denied 报错

探讨在 Windows 环境下配置 GitHub SSH 密钥时,为何终端测试成功但 git clone 失败,并提供根本解决方案。

一、现象描述

在 Windows 环境下配置 GitHub SSH 密钥时,常常会遇到一个充满迷惑性的报错现象。当我们在终端直接测试 SSH 连接:

ssh -T git@github.com

终端会正常返回欢迎信息,证明密钥配置无误:

Hi your_username! You've successfully authenticated...

但紧接着执行 git clonegit push 命令时,却直接报错拒绝访问:

git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

二、问题排查

现象表现为同一台电脑对同一份密钥的读取结果前后矛盾。为了确认 Git 在执行网络请求时到底发生了什么,我们可以开启 Git 的 SSH 调试模式。在终端临时注入环境变量,强制输出 Git 底层的 SSH 调用日志:

GIT_SSH_COMMAND="ssh -v" git clone git@github.com:your-name/your-repo.git

通过详细日志可以观察到,git clone 并没有调用系统默认的 SSH 程序,也没有去正确的 ~/.ssh 目录下寻找刚刚配置好的私钥。

三、原因分析

这个问题的核心在于:Windows 系统中同时存在两个互不相通的 SSH 程序。

  graph TD
    A[终端环境] --> B{执行指令}
    B -->|ssh -T| C[Windows 原生 OpenSSH]
    B -->|git clone| D[Git 自带内部 SSH]
    
    C -->|读取 C:\Users\用户名\.ssh| E[找到私钥]
    E --> F[连接 GitHub 成功]
    
    D -->|MSYS2 模拟环境| G[路径解析偏差 / 无法读取 ssh-agent]
    G --> H[找不到私钥]
    H --> I[Permission denied]

1. Windows 原生 OpenSSH

从 Windows 10 开始,微软内置了一套原生的 OpenSSH 工具,路径为 C:\Windows\System32\OpenSSH\ssh.exe。执行 ssh -T 时,系统默认唤醒的是这个原生程序。它能准确识别当前 Windows 用户的 ~/.ssh 目录并读取私钥,因此测试顺利通过。

2. Git for Windows 自带 SSH

安装 Git 时,为了兼容旧版 Windows,Git 官方打包了一个专属的 SSH 程序,路径通常在 C:\Program Files\Git\usr\bin\ssh.exe。执行 git clone 时,Git 会强制调用自带的内部 SSH。由于该程序运行在一个模拟的 Linux 环境 MSYS2 中,它对文件路径的解析或对 Windows 系统 ssh-agent 密钥代理服务的读取存在偏差。这导致它在连接 GitHub 时交不出密钥,从而被服务端拒绝。

四、解决方案

明确了问题是环境割裂导致的,修复逻辑就是统一底层调用。我们需要通过 Git 的全局配置,覆写它的默认行为,强制 Git 放弃内部自带的 SSH,转而调用 Windows 系统的原生 SSH 程序。

在终端执行以下配置命令:

git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"

执行完毕后,Git 的网络操作与系统的 ssh 命令彻底打通,底层调用的都是同一个能正确找到密钥的程序。再次执行 git clone 即可顺利拉取代码。

五、总结

在开发环境搭建中,多套工具链附带的同名依赖组件往往是引发底层冲突的根源。遇到配置生效不一致的情况,利用 GIT_SSH_COMMAND="ssh -v" 这类环境变量暴露出底层的真实调用路径,是打破信息差、快速定位问题的有效手段。

使用 Hugo 构建
主题 StackJimmy 设计