Git fetch 失败: gnutls_handshake() failed 的排查与修复

在项目中执行 git fetch 时报错:

复制代码
fatal: unable to access 'https://git.example.com/rxx/demo_project.git/':
gnutls_handshake() failed: Error in protocol version

2. 表现

  • git fetch / git pull 均失败,无法访问远程仓库。
  • 报错信息固定为 gnutls_handshake() failed: Error in protocol version
  • 系统其他工具(如 curl)访问同一域名却正常。

3. 根因分析

3.1 服务器只支持 TLS 1.3

openssl s_client 实测远端服务器:

bash 复制代码
echo | openssl s_client -connect git.example.com:443 -tls1_2   # 失败
# error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
echo | openssl s_client -connect git.example.com:443 -tls1_3   # 成功

服务器对 TLS 1.2 握手直接拒绝,只放行 TLS 1.3。

3.2 git 客户端使用的 TLS 库不支持 TLS 1.3

  • 旧版系统 git(Ubuntu 18.04 自带 2.17.1)使用系统 gnutls 3.5.18,不支持 TLS 1.3。
  • 升级到 PPA 版 git 2.50.1 后依旧失败,因为 PPA 把 gnutls 版 libcurl 静态链接 进了 git 二进制:
    • ldd /usr/bin/git 看不到 libcurl 动态依赖(被静态打入)。
    • git -c http.sslBackend=opensslCould not set SSL backend to 'openssl': already set,说明编译时已固定为 gnutls。
  • 系统 curl 之所以正常,是因为它链接的是 openssl 版 libcurl(libcurl.so.4)。

3.3 关键点

组件 TLS 后端 TLS 1.3 支持 结果
系统 curl OpenSSL 1.1.1 支持 正常
系统 git 2.17.1 gnutls 3.5.18 不支持 失败
PPA git 2.50.1 静态 gnutls libcurl 不支持 失败

4. 解决办法:从源码编译 git,链接 openssl 版 libcurl

核心思路:让 git 使用系统已有的 openssl 版 libcurl.so.4,而不是默认的 -lcurl(它会解析到 gnutls 版的 libcurl.so -> libcurl-gnutls.so 符号链接)。

4.1 下载源码

bash 复制代码
cd /tmp/opencode
curl -sL -o git.tar.gz https://github.com/git/git/archive/refs/tags/v2.50.1.tar.gz
tar xzf git.tar.gz
cd git-2.50.1

4.2 生成 configure 并配置

bash 复制代码
make configure
./configure --prefix=$HOME/git-local --without-tcltk CURL_LDFLAGS="-Wl,-l:libcurl.so.4"

注意:configure 生成的 config.mak.autogen 会覆盖为 CURL_LDFLAGS=-lcurl,需要手动改回:

bash 复制代码
sed -i 's|^CURL_LDFLAGS=-lcurl$|CURL_LDFLAGS=-Wl,-l:libcurl.so.4|' config.mak.autogen

4.3 编译并安装

bash 复制代码
make -j$(nproc)
make install

4.4 验证

bash 复制代码
# 确认 git-remote-http 链接 openssl 版 libcurl
ldd $HOME/git-local/libexec/git-core/git-remote-http
#   libcurl.so.4 => /usr/lib/x86_64-linux-gnu/libcurl.so.4
#   libssl.so.1.1  => /usr/lib/x86_64-linux-gnu/libssl.so.1.1

# 测试 fetch
$HOME/git-local/bin/git fetch origin   # 成功,exit=0

4.5 设为默认

bash 复制代码
echo 'export PATH="$HOME/git-local/bin:$PATH"' >> ~/.zshrc
# 新开终端生效

5. 总结

  1. 服务器只接受 TLS 1.3,客户端 TLS 库不支持则握手失败。
  2. PPA 版 git 静态绑定了 gnutls 版 libcurl,无法通过配置切换后端。
  3. 从源码编译 git 并强制链接 openssl 版 libcurl.so.4 即可解决。
相关推荐
Hvitur7 小时前
Linux安装Git【离线安装】
git
howard200512 小时前
6.4 Git安装与配置
git·安装配置
tryCbest16 小时前
git实现前后端分离项目提交同一个仓库
git·gitee
Mr.朱鹏16 小时前
Git 仓库同时推送到 Gitee 与 GitHub 配置指南
git·gitee·开源·github
Flynt1 天前
HN 382分热文里的终端小技巧,我实测了一遍,git pickaxe 最值
git·命令行
横木沉2 天前
IntelliJ IDEA 无法识别 Git:Git is not installed 问题解决
java·git·github·intellij-idea
为你学会写情书2 天前
Git 学习指南:从日常命令到多人协作与提交规范
git
东小黑2 天前
Git 仓库操作与 VSCode 使用指南
git·vscode·gitee
拼图2092 天前
Git常用语法
分布式·git·学习
ShineWinsu3 天前
对于Git:基础操作的超详细保姆级解析
linux·c++·git·面试·备份·管理·版本控制器