最近在向 GitHub 推送代码时,网络又开始抽风。无论是 git push 还是 git pull,都大概率会卡在某个地方,然后给我一个冰冷的 Connection refused 或者 Connection reset。就算切换到 SSH 协议,有时也难逃一劫。

每次遇到这个问题都要重新搜索一遍解决方案,效率太低。为了防止以后自己忘记,也为了形成一个可以快速查阅的备忘录,我决定把几种主流的解决方案整理成一篇文章,彻底搞定这个问题。

1. 背景与常见错误

问题的核心在于本地网络环境与 GitHub 服务器之间的网络连接不稳定或存在策略性阻断。这通常会导致以下几种典型的错误信息:

通过 SSH 协议访问时:

ssh: connect to host github.com port 22: Connection refused
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

或者在测试 SSH 连通性时出现:

$ ssh -T git@github.com
Connection reset by 20.205.243.160 port 443

我们的目标就是通过配置代理,让 Git 的网络请求绕过不稳定的链路,从而实现稳定访问。

2. 准备工作:确认代理端口

在开始配置之前,必须先确认本地代理软件监听的协议和端口。如果这里搞错了,后续的所有配置都将无效。

  • Clash: 通常 HTTP 代理端口为 7890,SOCKS5 代理端口为 7891
  • V2RayN/V2RayU: 通常 HTTP 代理端口为 10808,SOCKS5 代理端口为 10809
  • Shadowsocks: 通常 SOCKS5 代理端口为 1080

提示:具体端口请以代理软件设置界面显示的为准。

3. 方案一:通过 SSH 配置代理

这个方案是我最推荐的,因为它只对 github.com 的 SSH 连接生效,不会影响其他任何工具或网站的访问,而且配置一次后就无需再关心。它适用于远程仓库地址格式为 git@github.com:user/repo.git 的情况。

步骤 1: 编辑 SSH 配置文件

打开终端,使用你熟悉的编辑器(如 vimnanovscode)编辑 SSH 用户配置文件。如果文件不存在,这个命令会自动创建它。

# 可以用nano
nano ~/.ssh/config

步骤 2: 添加代理配置

在打开的文件中,添加以下内容。请注意区分操作系统,因为它们使用的代理命令工具不同。

对于 macOS / Linux 用户:

Host github.com
    Hostname ssh.github.com
    Port 443
    User git
    # 使用 nc (netcat) 作为代理命令,-x 参数表示 SOCKS5 代理
    # 如果你的代理是 HTTP 类型,可以尝试将 -x 改为 -X connect
    ProxyCommand nc -v -x 127.0.0.1:7891 %h %p

对于 Windows (Git Bash) 用户:

Host github.com
    Hostname ssh.github.com
    Port 443
    User git
    # Git for Windows 自带了 connect.exe 工具
    # -S 参数表示 SOCKS5 代理,-H 参数表示 HTTP 代理
    ProxyCommand connect -S 127.0.0.1:7891 %h %p

注意:请务必将上述命令中的 127.0.0.1:7891 替换为你自己在第二步中确认的真实代理地址和端口。如果你的代理是 HTTP 类型,记得将 nc-x 参数或 connect-S 参数相应地修改。

配置参数解释

  • Hostname ssh.github.com: 使用 GitHub 官方提供的备用 SSH 域名,可以有效规避某些针对 github.com 的 DNS 污染。
  • Port 443: 将 SSH 连接的默认 22 端口切换到 443 (HTTPS) 端口,这可以绕过部分防火墙对 22 端口的封锁。
  • ProxyCommand: 这是核心指令,它告诉 SSH 在连接 github.com 时,不要直接发起 TCP 连接,而是执行一个指定的命令来建立通道。%h%p 是占位符,分别代表目标主机名(Hostname)和端口(Port)。

步骤 3: 测试连接

保存配置文件后,执行以下命令测试 SSH 连通性:

ssh -T git@github.com

如果看到以下欢迎信息,就说明配置成功了!

Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.

4. 方案二:通过 HTTPS 配置全局代理

如果你的仓库地址是 https://github.com/user/repo.git 格式,则需要配置 Git 的 http.proxyhttps.proxy。这种方式会影响所有使用 Git 的 HTTPS 请求,而不仅限于 GitHub。

提示:如果你的仓库当前是 SSH 格式,可以先用 git remote set-url origin https://github.com/user/repo.git 切换到 HTTPS 格式。

步骤 1: 设置 Git 全局代理

执行以下命令,将 Git 的所有 HTTPS 流量都指向你的本地代理。

# 分别为 HTTP 和 HTTPS 协议设置代理
# 注意这里的代理地址格式是 http://<host>:<port> 或 socks5://<host>:<port>
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890

步骤 2: 取消代理(需要时)

如果后续不需要代理了,可以通过 --unset 参数来移除配置。

git config --global --unset http.proxy
git config --global --unset https.proxy

5. 方案三:仅为 GitHub 配置 HTTPS 代理

这是方案二的优化版。如果你不希望代理影响到其他 Git 仓库(例如 Gitee 或 GitLab),只想针对 GitHub 进行配置,可以使用下面的命令。

设置针对性代理

git config --global http.https://github.com.proxy http://127.0.0.1:7890

取消针对性代理

git config --global --unset http.https://github.com.proxy

这个配置为一个特定的 URL 域设置了专有的代理。

6. 避坑指南与常见问题

在折腾的过程中,我还是踩了一些坑,这里一并记录下来,方便日后快速排查。

  1. Windows 下提示 command not found: connect

    • 原因分析: 多数情况下,Git for Windows 自带 connect.exe。如果出现此提示,可能是 PATH 环境变量未正确配置,或者 Git 安装不完整。
    • 解决方案: 可以在 SSH 配置中直接使用 connect.exe 的绝对路径来规避 PATH 问题。
      # 将 ProxyCommand 指向 connect.exe 的绝对路径
      ProxyCommand /mingw64/bin/connect -H 127.0.0.1:10808 %h %p
      
  2. 首次连接提示主机真实性无法确认

    • 现象: 在执行 ssh -T git@github.com 时,终端可能会显示以下信息:
      The authenticity of host '[ssh.github.com]:443 ([140.82.113.37]:443)' can't be established.
      Are you sure you want to continue connecting (yes/no/[fingerprint])?
      
    • 解决方案: 这并非错误,而是 SSH 的标准安全机制。它表示这是你第一次连接该主机,需要你确认其公钥指纹。

      提示:直接输入 yes 并回车即可。SSH 会将该主机的公钥信息保存到 ~/.ssh/known_hosts 文件中,下次连接时便不会再提示。

  3. 连接测试时出现 Connection refused

    • 原因分析: 这是最常见的错误,表明你的 Git/SSH 请求根本没有成功到达代理服务器。
    • 排查清单:
      • 检查代理软件是否已启动并处于正常工作状态。
      • 再次核对 ~/.ssh/configgit config 中填写的端口号是否与代理软件实际监听的端口完全一致。一个数字的错误就会导致失败。
  4. SSH 连接时出现 Broken pipe 错误

    • 原因分析: 这个错误通常是代理协议类型不匹配导致的。例如,你的代理是 HTTP 类型,但在 ProxyCommand 中却错误地使用了 -S (SOCKS5) 参数。
    • 解决方案: 确保 connect 命令的参数与你的代理协议一致。
      • 如果代理是 HTTP 类型,应使用 -H 参数。
      • 如果代理是 SOCKS5 类型,应使用 -S 参数。
      # 示例:将错误的 SOCKS5 参数(-S)修正为正确的 HTTP 参数(-H)
      ProxyCommand connect -H 127.0.0.1:10808 %h %p