背景说明

问题发生在疫情隔离、居家办公时,笔者使用自己的笔记本电脑修了一个 hotfix,正要推送呢,却一直在卡在命令行终端的交互中,输入任何字符都没有用,只能强制中止。稍息片刻,再次测试,依然卡住,心情十分郁闷,只得放下工作,着手分析修复。

首先,先交代一下操作系统的基础信息,系统是 Windows 10 的最新 Build;Git 是 git scm 刚下载安装的,附带安装了 MinGw,其模拟了一些类似 Linux Bash 命令; 除此之外,还装了 Putty 用于 SSH 连接,和公私钥对的生成。

$ systeminfo
Host Name:                 LAPTOP-**********
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.19044 N/A Build 19044
...

问题现象

接着,描述一下问题发生时的症状。在笔者输入了 git push 后,映入眼帘的不是预期的 git 正在压缩处理多少对象,计算出多少数据差异,准备往远端 push 之类的输出。而是一串奇怪的提示:

$ git push
The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's ssh-ed25519 key fingerprint is:
ssh-ed25519 256 91:90:84:b4:b2:**:**:**:**:8e:be:6b:38:74:1b:f0
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)

意思就是要不要保存远程主机的公钥。然而,输入 y 或者 n,乃至是任意字符都没有反应,最后只能用 ctrl+c 强制终止掉。

解决方案

出师未捷

带着关键词放狗去搜,在一篇 StackOverflow 回答中 [^1] Roman Starkov 提到了一种可能的解决方案,是说用 putty 自带的 plink 去手动模拟一遍获取的 key 的过程,如果模拟成功,该 host key 存下来了,那么之后的 git push 命令就能直接使用。

$ plink <your-git-server> -P <port> -l <username> -i <private_key>

然而,这个 accepted answer 却没有帮助,笔者尝试使用 Putty Plink 连接,并无输出同样的提示,让笔者在 y/n 中做选择。

事情的转机

不过,虽然答案描述的路径不可行,但是却给了笔者一个提示,为啥 git push 时,会调用 plink,这其中必有蹊跷。一般来说,软件开发中,外部的依赖包的配置信息,要么放在配置文件或本地数据库中,要么通过环境变量来传递;如果是在 Windows 还有一种可能是通过注册表的方式来记录。

笔者猜想 git 这种纯 UNIX 风格的尿性,有很大概率是通过环境变量的方式传递的,尝试在 mingw 的终端输入(注意不是 Windows 自带的 cmd):

$ env | grep -i "plink.exe"
GIT_SSH=E:\ProgramFiles\PuTTY\plink.exe
> set | find /I "plink.exe"
GIT_SSH=E:\ProgramFiles\PuTTY\plink.exe

这和 mingw bashplink 可执行文件的路径是吻合,同样,也可以通过 cmdwhere 命令来验证。

# mingw bash
$ which plink
/e/ProgramFiles/PuTTY/plink
; windows cmd
> where plink
E:\ProgramFiles\PuTTY\plink.exe

果不其然🤭,git push 是通过 GIT_SSH 这个环境变量,来获取应该用哪个 SSH 连接工具,去跟 remote server 建立连接。

解决方案

既然 GIT_SSH 指向哪个可执行文件是解决问题的关键,那么很自然的想法就是改成 mingwssh 命令所对应的文件。

mingw 终端的 sshcmd 命令行的 ssh 都是可以正常使用的,无任何的卡顿,说明 puttyssh 命令是两套不同的 SSH(Secure Shell Protocol) 协议的实现。

临时解法

我们先看看 ssh 命令来源哪里:

> where ssh
C:\Windows\System32\OpenSSH\ssh.exe

再让 GIT_SSH 指向正确的位置:

set GIT_SSH=C:\Windows\System32\OpenSSH\ssh.exe

重新发起 git push,一切正常~ bingo 🐤


操作过程详见视频:


视频 1: 临时修复步骤

最终解法

每次都设置环境变量,不是长久之计。我们可以修改系统级别的环境变量,将其记忆下来,操作步骤如下:

  1. 按下 win+r,唤出运行对话框;
  2. 输入 sysdm.cpl,在弹出的窗体中选择 "Advanced"(高级)选项卡;
    或直接输入 SystemPropertiesAdvanced 可直达;
  3. 在该界面中的右下方,找到 "Environment Variables"(环境变量);
  4. 在新窗体的 "System Vairiables" 系统变量表中,找到并修改 GIT_SSH 环境变量的值;
  5. 重启命令行终端即可。

set_env_var.webp
图 1: 设置环境变量

总结

Windows 用作休闲娱乐固然是很好用,但是配开发环境难免遇到一些奇奇怪怪的坑,山重水复疑无路,内心曾几度动摇,想要改用 Linux 时,柳暗花明又一村!🦚

参考链接

  1. Git Server Host key not cached | StackOverflow

添加新评论