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 即可解决。
相关推荐
wdfk_prog5 小时前
GitHub push 失败:如何扫描并清理 Git 历史中的大文件
git·elasticsearch·github
大明二代7 小时前
使用 Traefik、cert-manager 和 DNS-01 为内网 Kubernetes 服务配置 HTTPS
git·kubernetes·flux
小芒果_018 小时前
git常用命令速查
大数据·git·elasticsearch
2501_930472449 小时前
腾讯云助手规范化Git提交记录
git·elasticsearch·腾讯云
风尘小子20 小时前
git的.gitignore文件中文件和目录配置
git
Tanner_SL1 天前
Linux笔记之GIT常用命令
linux·git
醉颜凉1 天前
Jenkins与Git集成完全指南:从基础配置到自动触发构建
运维·git·jenkins
樱花落木兰1 天前
Git 超全零基础教程|三区原理、全套命令、分支协作、冲突解决、IDEA 集成(面试必备)
ide·git·json·github
云和数据.ChenGuang1 天前
git revert回退问题
java·服务器·人工智能·git·fastapi·强化学习
伞伞悦读1 天前
【第12期】Windows 开发环境备份与恢复:软件、环境变量、Git、conda 和 Docker 卷完整方案
git·docker·conda