首页 / 资讯中心 / 文章详情

Git克隆报错 result=35?从TLS握手到代理配置的排查指南

Git克隆报错 result=35?从TLS握手到代理配置的排查指南 ★ FEATURED ARTICLE
1. 报错第一现场现象、环境与信息采集先说结论这个报错我前前后后碰到过多次每次根因都不一样但报错文本几乎一模一样。如果你正卡在error: RPC failed; result35, HTTP code 0这行输出上别急着怀疑网络先冷静下来把现场信息采集完整再动手。我最近一次遇到它是在某内部代码托管平台拉取一个较大的 monorepo 仓库。仓库体积不算夸张大概几百MB历史提交两万多条。我执行git clone https://git.example.internal/group/project.git进度条走到差不多 30% 的时候终端突然吐出一行error: RPC failed; result35, HTTP code 0 fatal: the remote end hung up unexpectedly注意报错后面往往还会跟一行fatal: the remote end hung up unexpectedly很多人只盯着第一句看实际上第二句才是真正的死亡宣告——远程服务端在传输中途把连接掐断了。我当时的客户端环境是 Windows 11 上的 Git for Windows 2.40系统代理配置过公司网络出口还有一层 HTTPS 扫描。这个组合本身就埋了好几颗雷。遇到任何报错我建议你先做三件事记录完整报错原文、确认 Git 版本、确认当前仓库的远程地址协议。很多人只复制了中间一行就上网搜结果搜出来的解决方案跟自己的环境对不上来回试好几轮问题没解决心态先崩了。git --version git remote -v git config --list --show-origin这三条命令能帮你在五分钟内把客户端版本、远程地址、有效配置摸清楚。后面排查代理、缓冲区、SSL 设置的时候这个清单能让你少走很多弯路。2. result35 和 HTTP code0 到底在说什么报错里的两个关键数字很多人没搞懂含义就直接去搜加大 postBuffer这其实是本末倒置。先花两分钟理解错误码能帮你快速缩小排查范围。第一个数字result35这个 result 实际上来自 Git 底层调用的 libcurl。curl 的错误码表里35 对应的是CURLE_SSL_CONNECT_ERROR意思是 SSL/TLS 握手阶段出了问题。可能是证书校验失败可能是 TLS 握手被中间设备干扰也可能是客户端和服务端在加密套件上谈不拢反正 HTTP 请求根本没机会正常发出。第二个数字HTTP code 0它表示 HTTP 响应码从未产生。正常情况下列表两位数响应码至少是三位数比如 200、403、502。0 意味着请求压根没到达 HTTP 层连接在更底层的 TLS/SSL 握手阶段就中断了。一句话总结这是传输层的 SSL/TLS 握手失败不是服务器拒绝请求也不是仓库本身有问题。理解了这一点你就知道为什么网上那些改 postBuffer的答案时灵时不灵——如果问题出在 SSL 握手你把缓冲区调得再大连接也根本建立不起来完全是两个层面的问题。而如果问题出在传输中途的数据包丢失加大缓冲区才可能有效。同样是result35, HTTP code 0实际场景差异很大这也是这个报错最迷惑人的地方。我把常见的 curl 相关错误码列个表方便你对照错误码含义说明35SSL connect errorTLS/SSL 握手失败常见于代理、证书、中间设备干扰56Failure receiving network data传输过程中连接中断可能来自网络超时或服务端切断18Transferred a partial file下载到一半数据不完整往往和缓冲区上限有关92HTTP/2 stream error流式传输被中断常出现在 HTTP/2 协议下的大仓库拉取从报错文本看result35 是握手阶段的问题HTTP code0 是还没到 HTTP 层的佐证。二者互相印证方向已经很明确你的 git 客户端在和服务端建立安全连接时被某个环节拦住了。3. 逐项排查三类高概率根因的定位过程明确了是 SSL/TLS 握手失败接下来就是一套标准排查流程。我按概率从高到低排列三类原因你可以照着顺序测每一步都有明确的命令来判断。3.1 第一嫌疑网络中间层对 TLS 握手的干扰这类场景最常出现在公司网络、校园网、公共 Wi-Fi 里。很多企业会在出口部署 HTTPS 流量检测或 SSL 卸载设备它会把你的 TLS 连接拦下来看一眼再放行。问题在于Git 客户端和代码托管平台之间的证书链校验一旦跨越了中间设备就很容易出现握手失败。我遇到的那次最后定位到的根因就是网络出口的 HTTPS 扫描策略把 git 的 TLS 握手掐断了。因为用浏览器访问同一个仓库页面完全正常浏览器能容忍一些证书链路异常但 Git 使用的 libcurl 校验逻辑更严格直接拒绝连接。怎么判断是不是这种情况你可以在命令行手动走一次 TLS 握手curl -v https://git.example.internal/group/project.git/info/refs?servicegit-upload-pack注意观察输出里SSL connection using TLS或者CONNECTED之类的关键行以及是否有证书链告警。如果 curl 能正常返回 200而 git clone 还是报 35那问题往往出现在 git 客户端的特定配置上。如果 curl 本身就失败那基本可以确定是网络或服务端的问题。还有一个更容易操作的判断方式换手机热点试一下。如果你的电脑在热点网络下能正常 clone 同一个仓库那就说明是办公网络的中间设备在干扰。我实测过这个方案定位速度非常快。3.2 第二嫌疑本地代理配置污染了 git 传输通道第二个高概率原因是本地代理设置。这个坑特别隐蔽因为很多时候你的系统代理是正常的浏览器访问也没问题但 git 不读系统代理只读自己的配置或者反过来——git 读到了不该读的代理配置导致握手被代理服务器拒绝。检查 git 自己的代理配置git config --global --get http.proxy git config --global --get https.proxy再检查环境变量里有没有代理残留env | grep -i proxy我见过不少情况https_proxy环境变量指向一个已经挂掉的代理端口git clone 时 libcurl 努力连接那个死掉的代理握手当然失败报错就是这个 35。解决办法很简单临时清掉环境变量再试unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY git clone https://git.example.internal/group/project.git如果 git 自己有全局代理配置但当前网络不需要代理直接删除即可git config --global --unset http.proxy git config --global --unset https.proxy这里必须说清楚如果你的业务确实需要走代理访问外部托管平台那问题就变成你的代理是否支持 TLS 握手、证书是否可信属于另一个范畴。但从result35这个报错出发先厘清代理配置是正确的第一步。3.3 第三嫌疑HTTP 缓冲区上限和低版本 Git 的叠加问题如果上面两类都排除了报错还没消失那就轮到经典的缓冲区问题。这个场景通常发生在拉取大仓库或大文件时而且经常出现在 Git 版本较老的环境里。先说原理Git 走 HTTP(S) 协议时数据会分块传输每一块的大小由服务端和客户端的缓冲区共同决定。客户端接收侧的缓冲区上限由http.postBuffer控制默认值是 1MB老版本或者 5MB新版本。仓库体积大、单文件大、或服务端分块策略不合理时容易超过这个上限导致传输中断表现为RPC failed。但注意缓冲区问题导致的报错大多是 result56 或 18不一定是 35。只有当缓冲区问题恰好触发 TLS 层的超时重置时才会和 35 沾边。所以如果你严格按照前面的顺序排查排除掉中间设备和代理后再考虑加大缓冲区才有意义。git config --global http.postBuffer 524288000这个设置把缓冲区加到 500MB对于大多数仓库足够用了。但我要多说一句这属于能用但不太优雅的方案相比优化缓冲区更值得做的是把大仓库拆成小仓库、用 LFS 管理大文件或者改用 SSH 协议后面详细说。3.4 其它值得注意的隐藏因素TLS 版本和 CA 证书库还有两个冷门因素也容易触发 result35。第一是 TLS 版本协商问题老旧的 Git 客户端可能默认使用 TLS 1.0/1.1而服务端已经移除了对这些老版本的支持。第二是系统 CA 证书库不完整git 执行 SSL 校验时找不到对应根证书握手直接失败。判断 TLS 版本问题可以用 curl 指定版本测试curl --tlsv1.2 -v https://git.example.internal/如果指定 TLS 1.2 能通不指定就失败说明客户端默认协商的 TLS 版本过旧需要升级 Git 版本。判断 CA 证书库问题可以先临时关闭校验再测试GIT_SSL_NO_VERIFYtrue git clone https://git.example.internal/group/project.git注意这条命令只是用来定位问题不要作为长期方案。如果关闭校验后 clone 正常说明正是证书链验证环节出了问题优先检查系统证书、公司自签证书的安装情况而不是一直关着校验裸奔。自签证书可以通过git config http.sslCAInfo指向证书文件来信任。4. 分策略修复从最小干预到最彻底解决排完查、定完位接下来就是动手修复。我按照干预程度从小到大给你整理了几套策略每套都给出适用场景。4.1 策略一清理配置与锁定协议如果你定位到是代理配置或某个全局配置项在捣乱最直接的修复方式是清理配置同时把 git 的 HTTP 版本锁定到更稳定的协议上。对于 HTTP/2 协议某些中间设备对它的支持并不完善也会导致类似 35 的握手异常。可以强制 Git 使用 HTTP/1.1git config --global http.version HTTP/1.1这个配置我实际用下来对于 HTTP/2 被中间设备干扰的场景有奇效。原理是 HTTP/2 的多路复用和 TLS 握手方式和 HTTP/1.1 不同很多企业防火墙对 HTTP/2 的处理存在兼容性问题。如果刚才的 curl 测试发现系统证书链有问题而你又确定服务端证书合法那可以先更新系统的 CA 证书库。Windows 上用 Git 自带的证书库更新脚本macOS 上注意钥匙串访问权限Linux 上用包管理器更新 ca-certificates。这类问题在自建 Git 服务且使用内网签发证书的情况下尤其常见。4.2 策略二调整缓冲区与压缩参数如果定位到是传输过程中的大包问题标准的修复组合是调整缓冲区和压缩阈值。除了前面提到的http.postBuffer还有一个容易被忽略的配置git config --global core.compression 0把压缩级别设为 0 表示不做压缩。为什么有人说这样能提速因为服务端发送数据时如果压缩很耗 CPU容易在传输过程中超时尤其对于本身就是文本压缩率很高的代码仓库压缩二次收益不大。但注意这是针对老服务端 CPU 性能不足场景下的偏方对于新版本 Git 服务端,这个配置一般用不上。还有一组配置针对 HTTP 请求的并发行为git config --global http.lowSpeedLimit 1000 git config --global http.lowSpeedTime 30它的含义是如果传输速度低于 1000 字节/秒且持续 30 秒Git 就放弃这次请求。这个配置本身是防止卡死的假传输但如果你网络偶尔抖动、瞬时会话慢它反而会让 Git 误判并主动掐断连接。遇见诡异的 35也可以尝试把这些值调低或调高来看是否有变化。4.3 策略三切换传输协议绕开 HTTPS 的老问题如果问题确认出在 HTTPS 这个传输链路上与其反复调参不如直接换一条路。两个方向方向一改用 SSH 协议。SSH 走的是完全不同的加密隧道和认证方式不经过 HTTP/TLS 层天然规避了 result35 这类问题。很多自建 Git 服务同时开放 HTTPS 和 SSH你只需要把远程地址从https://改成ssh://git或者git形式然后重新拉取。前提是你已经在托管平台配置好了 SSH 公钥。这个方法对中间设备干扰 HTTPS这类场景堪称一刀解决。方向二尝试在 HTTP 协议下使用git://。不过git://协议因为安全原因很多平台已经不支持适用面窄这里不展开。4.4 策略四浅克隆与分块拉取兜底如果仓库本身就很大、历史很悠久即使解决了握手问题完整克隆也可能继续触发其它传输问题。这时候可以用浅克隆先拿到一份工作副本git clone --depth 1 https://git.example.internal/group/project.git--depth 1只拉取最近一次提交传输数据量会大幅下降。如果需要历史可以之后用git fetch --unshallow逐步补全或者用--filterblob:none做 blobless clone先只下载提交树用到哪个文件再按需拉取git clone --filterblob:none https://git.example.internal/group/project.git这是我在大仓库场景下比较推荐的方案。配合稀疏检出sparse checkout你甚至可以只拉取某个子目录的代码用最小成本解决拿到仓库但拉不动的问题git clone --filterblob:none --sparse https://git.example.internal/group/project.git cd project git sparse-checkout set docs/这套组合拳下来大多数体积型报错都能绕过去。5. 修复后验证别漏掉假恢复修复完不要急着收工我见过太多次改完配置后 clone 成功但第二天又坏了的情况原因就是没有验证到位。给你一份验证清单按照顺序执行。第一步确认 clone 完整性。git clone https://git.example.internal/group/project.git cd project git fsck --fullgit fsck --full会检查对象库的完整性如果有缺失或损坏的对象它会明确报出来。这一步能确认你拿到的仓库不是残缺的。第二步验证计数对象的容量。完整性之外还要看对象数量是否合理git count-objects -vH正常输出会包含count、size等字段。如果 count 值很小但 repo 实际很大说明浅克隆生效或者你的 clone 没有拿到全量数据——这取决于你是否刻意做了浅克隆如果是刻意为之这只算预期状态不算问题。第三步验证 commit 历史可追溯。git log --oneline -5如果能看到近期的提交记录说明历史链是通的。第四步确认远端分支和标签。git branch -a git tag没有分支和标签的仓库是残缺的尤其是 tag很多人 clone 完会忘记检查。再提醒一个常见的假恢复场景你临时用GIT_SSL_NO_VERIFYtrue试通了 clone然后把命令写进了脚本从此所有操作都是裸奔状态。表面看是修复了实际上是把安全验证全关了这是最典型的假恢复。这种方案只允许用在线排查阶段绝不能进生产脚本。6. 同类问题预防让 result35 从你的日常里消失诊断和修复做完最后聊聊怎么防止它反复出现。尤其是团队协作和 CI/CD 环境里一次报错就会卡住所有人的流程值得做几件一劳永逸的事。6.1 统一 Git 版本消灭老版本兼容问题我见过不少 result35 的案例升级 Git 版本之后就消失了。原因很简单老版本 libcurl 或 Git 的 TLS 协商逻辑存在已知问题新版本早已修复。团队内部可以用 Docker 镜像或者共用的安装包来统一版本至少确保大版本一致。Git 2.30 及以上版本对 TLS/HTTP2 的处理已经稳健得多。6.2 把大仓库治理纳入日常仓库太大本身就是一个慢性病。一次性拉取几百 MB 甚至几个 GB 的项目出问题只是时间问题。建议超过 100MB 的二进制文件一律走 LFS有明确边界的子模块拆成独立仓库维护一个专门的瘦身脚本定期清理历史中的大文件clone 环节默认使用--filterblob:none或--depth 1这几招是我自己维护大仓库时实践出来的确实能显著降低传输类报错的概率。6.3 建立团队排查模板最后分享一个习惯把一次完整的排查过程沉淀成模板下次遇到同类问题照着走一遍效率能提升不少。我的模板大致长这样记录报错原文和发生阶段clonefetchpush检查 git 版本和 remote 地址检查 git 代理配置和环境变量代理用 curl 测试同地址的 TLS 握手换网络验证是否是中间设备问题根据定位结果选择对应修复策略每次都从最基础的信息采集开始不要跳步。很多时候你以为自己在排查 result35查到最后发现是另一个问题引发的连锁反应这时候以前的排查记录就能帮你快速排除错误路径。7. 写在最后的一次实战复盘回到我开头提到的那个 monorepo那次排查我折腾了整整一个下午期间试过调 postBuffer、改 compression、反复清代理配置全都无效。最后突然想起来公司网络对 HTTPS 请求有专门的检测策略我换到手机热点一测同一个仓库不到三分钟就 clone 完了。那一刻才确定是中间设备问题。经历那次之后我现在遇到任何传输类报错第一反应永远是先换网络再试一次。这个动作的真实价值超过了调任何参数——它能把链路问题和客户端配置问题瞬间切开省下的时间远超几小时的盲试。如果你读完这篇之后正守着终端发愁不妨先走出工位把电脑连上手机热点重新跑一次 clone。运气好的话三分钟就能看到进度条走到 100%。如果热点也救不了再回来按文章里的链路逐项排查每一个分支都有明确的命令对应不会再像无头苍蝇一样乱撞。
阅读完成 · 觉得有帮助?
咨询建站