返回

Windows Git SSH Key无效?Push输密码原因与解决

windows

头疼!Windows 下 Git 咋就不认我的 SSH Key?原因分析与解决方案

哥们儿,是不是也遇到过这种情况:在 Windows 上兴冲冲配好了 SSH Key,用 ssh -T 命令测试 GitLab 连接,那叫一个顺畅,嗖嗖地就提示你输入密钥的密码,然后告诉你 "Welcome to GitLab, @username!"。

> ssh -T [email protected]
Enter passphrase for key 'C:\Users\[username]/.ssh/id_ed25519':
Welcome to GitLab, @000[...]!

接着你用 git remote set-url origin [email protected]:000[...]/project.git 把远程仓库地址也换成了 SSH 格式,也没报错。

可偏偏,等你 git push 的时候,它老人家不按套路出牌,不问你要 SSH 密钥的密码 (passphrase),反而弹窗或者在命令行里管你要 GitLab 账户的密码 (Password for [email protected])。这不就白瞎了咱配的 SSH Key 嘛!

更让人郁闷的是,咱还照着 GitLab 官方文档在 ~/.ssh/config 文件里指定了密钥:

Host gitlab.lrz.de
 HostName gitlab.lrz.de
 IdentityFile ~/.ssh/id_ed25519

结果呢?然并卵。Git 依然我行我素,对这个配置文件视而不见。在 Linux 上明明玩得转,怎么到了 Windows 这就水土不服了呢?

别急,这事儿不少人都碰上过。咱们来掰扯掰扯到底是咋回事,再对症下药。

一、问题现象:SSH 测试通过,Git Push 却要密码?

简单概括下,就是:

  1. 通过 ssh -T git@your-gitlab-host.com 直接测试 SSH 连接是成功的,能正常提示输入密钥的密码短语 (passphrase)
  2. Git 的远程仓库 URL (git remote -v) 确认是 SSH 格式 (如 [email protected]:group/project.git)。
  3. 执行 git pushgit pull 等操作时,Git 却提示输入 GitLab 账户的登录密码 (password) ,而不是 SSH 密钥的密码短语。
  4. 可能尝试在 ~/.ssh/config 中指定了 IdentityFile,但 Git 似乎没有读取它。

手头的 Git 版本是 git version 2.35.1.windows.1

二、为啥会这样?深挖问题根源

出现这种“精分”现象,通常是 Git 在 Windows 上调用 SSH 功能时,没找到正确的 SSH 客户端,或者没加载到你指定的密钥。具体来说,可能有以下几个原因:

  1. SSH 客户端混淆 :Windows 环境下可能存在多个 SSH 客户端。比如系统自带的 OpenSSH (通常在 C:\Windows\System32\OpenSSH\),Git for Windows 自己捆绑的 SSH (通常在 Git 安装目录的 usr\bin下,如 C:\Program Files\Git\usr\bin\ssh.exe),甚至还有像 PuTTY 这样的第三方工具。Git 可能没有使用你期望的那个 SSH 客户端,导致 ~/.ssh/config 未被正确读取。
  2. SSH Agent 未运行或未加载密钥 :SSH Agent 是一个后台程序,可以缓存解密后的私钥,避免你每次连接都输入密码短语。如果 Agent 没启动,或者启动了但没有把你的私钥 id_ed25519 加载进去,那么即使 SSH 客户端配置对了,也可能因为找不到解密的密钥而失败,进而回退到其他认证方式(比如密码认证)。
  3. ~/.ssh/config 文件本身的问题
    • 路径问题~ 在 Windows 上通常指向用户的家目录,即 C:\Users\[username]。所以 ~/.ssh/config 对应的物理路径是 C:\Users\[username]\.ssh\config。确保文件名是 config,没有 .txt 之类的后缀。Windows 默认隐藏已知文件类型的扩展名,有时用户创建文本文件可能会不小心命名为 config.txt
    • 权限问题 :虽然在 Windows 上相对少见,但 .ssh 目录及其内部文件的权限过于开放,也可能导致 SSH 出于安全考虑拒绝使用它们。通常,.ssh 目录应该是 700 (用户完全控制,其他无权限),私钥文件 600 (用户读写,其他无权限)。
    • 内容格式 :虽然你的配置看起来没问题,但也要留意空格、换行等细节。
  4. Git 环境变量 GIT_SSHGIT_SSH_COMMAND 设置不当 :这两个环境变量可以用来指定 Git 使用哪个 SSH 可执行文件。如果它们被错误地设置了,或者指向了一个不认识你配置的 SSH 客户端,就会出问题。
  5. Windows 凭据管理器 (Credential Manager) 的干扰 :有时 Windows 的凭据管理器或者 Git 自带的凭据辅助程序 (如 Git Credential Manager Core) 可能会缓存旧的凭据或者尝试用它认为“更方便”的方式进行认证,从而绕过了 SSH Key。

既然找到了可能的原因,那我们就来逐个击破。

三、怎么办?多管齐下解决问题

针对上面分析的几种可能,我们提供几个解决方案。建议从简单到复杂逐一尝试。

方案一:检查并配置 SSH Agent

SSH Agent 是最常见的解决方案,因为它能一劳永逸地解决重复输入密码短语的问题,并且有助于 Git 正确找到密钥。

原理和作用:
SSH Agent (如 ssh-agent.exe) 是一个后台辅助程序,它负责管理你的 SSH 私钥。你可以将解密后的私钥(输入一次密码短语后)添加到 Agent 中,之后 SSH 客户端连接到服务器时,会先尝试从 Agent 获取密钥,无需再次输入密码短语。

操作步骤:

  1. 检查 SSH Agent 服务 (Windows 自带 OpenSSH Agent):

    • 按下 Win + R,输入 services.msc 打开服务管理器。
    • 找到 "OpenSSH Authentication Agent" 服务。
    • 如果它没启动,右键点击 -> "属性",将 "启动类型" 设置为 "自动" 或 "手动",然后点击 "启动"。
  2. 通过命令行启动 Agent 并添加密钥(适用于 Git Bash 或 PowerShell):

*   打开 Git Bash (推荐,因为它环境更接近 Linux)。
*   启动 `ssh-agent` (如果尚未运行):
    ```bash
    eval $(ssh-agent -s)
    # 你会看到类似这样的输出: Agent pid 12345
    ```
    **注意:**  `eval $(ssh-agent -s)` 是为了将 `ssh-agent` 输出的环境变量(如 `SSH_AUTH_SOCK` 和 `SSH_AGENT_PID`)设置到当前 shell 会话中,这样 `ssh` 和 `git` 命令才能找到这个 agent。如果直接执行 `ssh-agent -s`,环境变量不会在当前会话生效。

*   添加你的 SSH 私钥到 Agent:
    ```bash
    ssh-add ~/.ssh/id_ed25519
    ```
    或者指定完整路径:
    ```bash
    ssh-add C:/Users/[YourUsername]/.ssh/id_ed25519
    ```
    它会提示你输入该密钥的密码短语 (passphrase)。输入正确后,密钥就被加载到 Agent 中了。
  1. 验证密钥是否已添加:

    ssh-add -l
    

    如果看到你的密钥信息,说明添加成功。

  2. 再次尝试 git push

安全建议:

  • 密码短语一定要设置,并且要足够复杂。
  • Agent 缓存的密钥只在当前登录会话有效,或者直到 Agent 进程被杀死。在共享计算机上,使用完毕后可以考虑停止 Agent (ssh-agent -k) 或移除特定密钥 (ssh-add -d ~/.ssh/id_ed25519)。

进阶使用技巧:

  • 自动启动 SSH Agent 并加载密钥 :可以将 eval $(ssh-agent -s)ssh-add ~/.ssh/your_private_key 加入到你的 shell 配置文件中 (例如 Git Bash 的 ~/.bashrc~/.profile)。不过,每次启动 shell 都提示输入密码短语可能有点烦。
  • 使用 keychain (更高级的 Agent 管理)keychain 工具可以让你在登录系统时启动一次 Agent,并在所有新的 shell 会话中重用这个 Agent,通常只需在第一次登录时输入密码短语。Windows 上可能需要通过 Cygwin 或 WSL 使用。
  • Windows 10/11 自带 OpenSSH Agent :如前所述,启动 "OpenSSH Authentication Agent" 服务后,理论上它应该能被 Git 使用的 OpenSSH 客户端发现。使用 ssh-add 时,它通常会将密钥添加到这个系统级的 Agent。

方案二:明确指定 Git 使用的 SSH 命令

如果 Agent 正常,但 Git 还是固执己见,那可能是 Git 调用的 SSH 程序不对。我们可以强制 Git 使用特定的 SSH 可执行文件。

原理和作用:
Git 允许通过环境变量 GIT_SSH_COMMAND 或 Git 配置项 core.sshCommand 来指定执行 SSH 操作时具体使用哪个命令。这能确保 Git 使用的是一个能正确处理你的 ~/.ssh/config 和 SSH Agent 的客户端。

操作步骤:

  1. 找到你希望 Git 使用的 ssh.exe

    • 系统 OpenSSH (推荐,因为它通常能很好地与系统 Agent 配合):C:\Windows\System32\OpenSSH\ssh.exe
    • Git for Windows 自带 SSHC:\Program Files\Git\usr\bin\ssh.exe (你的 Git 安装路径可能不同)
  2. 方法 A: 通过环境变量 GIT_SSH_COMMAND (临时或会话级):
    在 Git Bash 或 PowerShell (根据你使用的命令行环境) 中设置:

    # Git Bash (注意路径格式)
    export GIT_SSH_COMMAND="C:/Windows/System32/OpenSSH/ssh.exe"
    # 或者 Git 自带的
    # export GIT_SSH_COMMAND="C:/Program Files/Git/usr/bin/ssh.exe"
    
    # PowerShell (注意路径格式和引号)
    $env:GIT_SSH_COMMAND = "C:\Windows\System32\OpenSSH\ssh.exe"
    # 或者 Git 自带的
    # $env:GIT_SSH_COMMAND = "C:\Program Files\Git\usr\bin\ssh.exe"
    

    设置后,在该命令行窗口中执行 git push 测试。

  3. 方法 B: 通过 Git 全局配置 core.sshCommand (永久,推荐此方法):
    打开 Git Bash 或任何可以运行 git 命令的终端:

    # 使用系统 OpenSSH (推荐)
    git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
    
    # 或者使用 Git 自带的 SSH
    # git config --global core.sshCommand "C:/Program Files/Git/usr/bin/ssh.exe"
    

    注意路径中的斜杠方向 :在 Git 配置中,即使是 Windows 路径,也建议使用正斜杠 /,或者双反斜杠 \\ (如 "C:\\Windows\\System32\\OpenSSH\\ssh.exe"),以避免转义问题。单反斜杠 \ 可能会被 Git 错误解析。

  4. 移除 GIT_SSH 环境变量 (如果已设置) :
    旧版本的 Git 使用 GIT_SSH 环境变量指向 ssh.exe。如果设置了这个变量,它可能覆盖 core.sshCommand。检查并清空它:

    # Git Bash (清空)
    unset GIT_SSH
    # PowerShell (清空)
    Remove-Item Env:GIT_SSH
    

    或者在系统环境变量设置中删除。

  5. 再次尝试 git push

安全建议:

  • 确保你指定的 ssh.exe 路径是可信的、官方的 SSH 客户端,而不是被篡改的恶意程序。

进阶使用技巧:

  • GIT_SSH_COMMAND 也可以包含 SSH 参数,例如,强制使用某个密钥而不依赖 Agent 或 config 文件:
    # Git Bash
    export GIT_SSH_COMMAND="C:/Windows/System32/OpenSSH/ssh.exe -i C:/Users/[YourUsername]/.ssh/id_ed25519_specific_for_gitlab_lrz_de"
    # Git Config
    git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe -i C:/Users/[YourUsername]/.ssh/id_ed25519_specific_for_gitlab_lrz_de"
    
    这样,Git 在连接时会总是使用 -i 参数指定的这个密钥文件。当然,你仍然需要输入这个密钥的密码短语(除非它已加载到 Agent)。
  • 诊断 SSH 行为 :可以通过 GIT_SSH_COMMAND="path/to/ssh.exe -vvv" 来让 Git 在执行 SSH 操作时输出详细的调试信息。这对于判断 SSH 客户端到底在干什么、读取了哪些配置文件、尝试了哪些密钥非常有帮助。
    例如,临时测试:
    # Git Bash
    GIT_SSH_COMMAND="C:/Windows/System32/OpenSSH/ssh.exe -vvv" git push
    

方案三:细致检查 ~/.ssh/config 文件

既然你已经创建了 ~/.ssh/config,但它似乎没起作用,我们得仔细看看它。

原理和作用:
~/.ssh/config 文件是 SSH 客户端的标准配置文件。当 SSH 客户端(如 ssh.exe)尝试连接到一个主机时,它会查阅这个文件,根据匹配的 Host 条目来决定使用哪个用户名、哪个端口、哪个身份文件(私钥)等。

操作步骤:

  1. 确认文件路径和名称

    • 在 Windows 文件资源管理器中,导航到 C:\Users\[YourUsername]\
    • 确保你有一个名为 .ssh 的文件夹 (注意,点开头)。
    • 在该 .ssh 文件夹内,确保你有一个名为 config 的文件,没有扩展名 ,不是 config.txt
      • 如何创建无扩展名文件 :可以在记事本或其他文本编辑器中编辑内容,然后“另存为”,在文件名框中输入 "config" (包含英文双引号),并将“保存类型”选为“所有文件 (.)”。
      • 显示文件扩展名 :在文件资源管理器的 "查看" 选项卡中,勾选 "文件扩展名",以确认文件名正确。
  2. 确认文件内容 :你的配置:

    Host gitlab.lrz.de
      HostName gitlab.lrz.de
      IdentityFile ~/.ssh/id_ed25519
      # 或者使用 Windows 绝对路径,注意斜杠
      # IdentityFile C:/Users/[YourUsername]/.ssh/id_ed25519
      # IdentitiesOnly yes  # (可选) 推荐添加,避免尝试其他默认密钥
    
    • Host gitlab.lrz.de:这个 Host 值必须与你 git remote -v 中看到的 git@ 后面的主机名完全一致
    • HostName gitlab.lrz.de:实际连接的主机名。
    • IdentityFile ~/.ssh/id_ed25519:指定私钥路径。~ 在 SSH 配置中通常能被正确解析为用户家目录。如果担心,可以换成绝对路径,但要用正斜杠 /
    • 推荐添加 IdentitiesOnly yes :这个选项告诉 SSH 只尝试 IdentityFile 指定的密钥,不要去试其他默认密钥 (如 id_rsa, id_dsa 等)。这在你有多个密钥,并且不想让 SSH 尝试不相关的密钥时非常有用。
  3. 测试 ~/.ssh/config 是否被 SSH 客户端读取:
    使用 Git Bash 或 PowerShell 执行:

    ssh -vvv [email protected]
    

    仔细查看输出。你应该能看到类似这样的行:

    • debug1: Reading configuration data /c/Users/[YourUsername]/.ssh/config (或类似路径)
    • debug1: Found Peirce ഇവിടെ to host gitlab.lrz.de in file /c/Users/[YourUsername]/.ssh/config line X
    • debug1: Setting implicit IdentityFile C:/Users/[YourUsername]/.ssh/id_ed25519 for host gitlab.lrz.de part of Host block X
    • debug1: Offering public key: C:/Users/[YourUsername]/.ssh/id_ed25519 ED25519 SHA256:xxxxxxxx
      如果这些信息没出现,或者 SSH 客户端尝试了错误的密钥,那说明 config 文件要么没被找到,要么内容不对,要么被其他设置覆盖了。

安全建议:

  • 确保 .ssh 文件夹的权限是 700 (仅用户完全控制)。
  • 私钥文件 (如 id_ed25519) 权限是 600 (仅用户读写)。
  • 公钥文件 (id_ed25519.pub) 权限是 644 (用户读写,组用户和其他用户只读)。
    在 Windows 上,可以通过文件属性 -> 安全 -> 高级来设置权限。通常,只要保证只有你自己的用户账户有权限访问 .ssh 文件夹和私钥文件即可。

进阶使用技巧:

  • ~/.ssh/config 可以为不同的主机配置不同的密钥和用户,非常灵活。
    例如:
    Host personal-gitlab
        HostName gitlab.com
        User git
        IdentityFile ~/.ssh/id_rsa_personal
        IdentitiesOnly yes
    
    Host work-gitlab
        HostName gitlab.company.com
        User developer_01
        IdentityFile ~/.ssh/id_ed25519_work
        IdentitiesOnly yes
    
    # 你提供的配置
    Host gitlab.lrz.de
      HostName gitlab.lrz.de
      # User git  # (通常 SSH URL 中已指定 git@...)
      IdentityFile ~/.ssh/id_ed25519
      IdentitiesOnly yes
    
    然后你就可以用 git clone personal-gitlab:my/project.gitgit clone work-gitlab:team/project.git

方案四:检查并处理 Windows 凭据管理器

有时候,Git for Windows 默认会使用 Windows 凭据管理器 (Git Credential Manager Core - GCM Core) 来存储和检索凭据。它主要是为 HTTPS URL 服务的,但某些情况下可能会对 SSH 行为产生非预期的影响,尽管可能性较低。

原理和作用:
GCM Core 目的是简化 HTTPS 认证,保存用户名和密码 (或 Token)。理论上它不应该干扰 SSH 密钥认证,因为 SSH 有自己的一套机制。但如果之前的某个环节让 Git 错误地认为需要密码,GCM Core 可能会介入并提示。

操作步骤:

  1. 检查 Git 凭据助手配置:

    git config --global credential.helper
    

    如果输出类似 manager-corewincred,说明启用了凭据助手。

  2. 临时禁用凭据助手 (用于测试):

    git config --global --unset credential.helper
    

    然后尝试 git push。如果这次正常使用 SSH Key 了,那说明凭据助手可能确实有影响。
    恢复凭据助手设置: 如果你想恢复它(比如你同时用 HTTPS 访问其他仓库),可以:

    git config --global credential.helper manager-core
    

    (根据你之前查到的值来恢复)

  3. 检查 Windows 凭据管理器:

    • 在 Windows 搜索中输入 "凭据管理器" (Credential Manager) 并打开。
    • 查看 "Windows 凭据" 和 "普通凭据" 中是否有与你的 GitLab 服务器相关的条目。
    • 如果找到可疑条目 (例如,保存了针对 gitlab.lrz.de 的密码),可以尝试删除它,然后重新测试 git push

安全建议:

  • 删除凭据管理器中的条目时要小心,确保你知道删的是什么。
  • 如果你确实依赖 GCM Core 管理 HTTPS 仓库的凭据,那么不应永久禁用它,而是应确保 SSH 的问题通过前述方案得到解决。

进阶使用技巧:

  • 理解 credential.helper 的作用域:--system, --global, --local。本地仓库的配置会覆盖全局,全局覆盖系统。
  • 如果同时使用 HTTPS 和 SSH,确保凭据助手不会干扰 SSH。通常,只要 SSH 配置正确(Agent, ~/.ssh/config, core.sshCommand),Git 会优先尝试 SSH Key。

总结一下排查思路

  1. 启动并配置 SSH Agent :这是最直接、最常用的方法。 (方案一)
  2. 明确指定 Git 使用的 SSH 客户端 :确保 Git "看对眼"。 (方案二)
  3. 仔细检查 ~/.ssh/config 文件 :路径、文件名、内容、权限。 (方案三)
  4. 使用 ssh -vvv [email protected] :这是调试 SSH 连接的终极武器,能告诉你 SSH 客户端在连接过程中到底发生了什么。
  5. 考虑凭据管理器的影响 :虽然少见,但有时也需要看看。 (方案四)

通常情况下,方案一 加上对 方案三~/.ssh/config 的仔细核对,就能解决大部分 Windows 上 Git 不使用 SSH Key 的问题。如果还不行,方案二 通过 core.sshCommand 指定一个已知工作正常的 ssh.exe (如系统自带的 OpenSSH),并结合 -vvv 参数进行调试,基本就能定位到症结所在了。

折腾环境是件麻烦事,但一旦搞定,以后用起来就舒心多了。祝你顺利!