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=openssl 报 Could 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 即可解决。
相关推荐
Madison-No710 小时前
Git版本控制工具(一)
git
小小小米粒18 小时前
重置本地git
大数据·git·elasticsearch
鶴哥只手遮天1 天前
第 8 章 工作区与检出:unpack-trees 与并行 checkout
git
xing-xing1 天前
git 相关命令总结
git
A-刘晨阳1 天前
GitLab + ArgoCD 实现 Kubernetes GitOps 自动化部署
运维·人工智能·git·kubernetes·自动化·云计算·argocd
ControlRookie2 天前
SyncBridge:一个 CODESYS 工程与 AI 之间工程师级的同步工具
git·ai编程·codesys·工业软件·controlrookie
鬼手点金2 天前
opencode-性能优化建议
java·人工智能·git·自动化·nanogpt
网络毒刘2 天前
开源 Aider 工作流实战:Git 提交驱动的 AI 结对,与 Cursor 何时互补
git·ai编程·cursor·aider
HRTOS2 天前
HRTOS 4.0 将长期维护:为什么版本号不再频繁变化
经验分享·git·单片机·51单片机
驭渊的小故事3 天前
linux 基础命令 + git 仓库创建和配置命令
linux·git