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 即可解决。
相关推荐
不老刘5 小时前
Antigravity 的 New Worktree 模式:给 AI 代理一个安全的“平行工位”
人工智能·git·ai编程·antigravity
光谱SpectrAI5 小时前
Windows 也中招:Git Bash 和 Node 仍信任泄露的 eMudhra 证书
git
YIN_尹6 小时前
【git原理与使用】git初识与安装
大数据·git·elasticsearch
Leo_Mr10 小时前
Vue3 项目配置 Git 提交规范(企业通用方案:husky + commitlint + cz-git + lint-staged)
git
jyOverQ11 小时前
Git rebase 和 merge 有什么区别?什么时候该用哪个?
git
晗夜未央11 小时前
跨仓库 Skill 换台电脑就失效?用 Git remote 校验项目
人工智能·git·python
Lsetea11 小时前
Git访问HTTPS证书不受信任:用URL级sslCAInfo限定私有CA范围
git·https·开发工具·ssl证书·ca证书
এ慕ོ冬℘゜1 天前
Git 基础入门|和 SVN 对比 + 四大区域 + 常用命令详解
git·svn
DevLoom_1 天前
macOS 命令行 curl/git 报 SSL 证书错误?eMudhra 事件完整修复指南
git·macos·ssl
keyipatience1 天前
Git学习(4)Git分布式优势与实战配置全解析
git·学习