Git LFS 推送故障排查与解决方案报告
Git LFS 推送故障排查与解决方案报告
一、问题描述
执行 git push 推送当前分支 wyx(领先 origin/wyx 11 个提交)时,遇到双重阻碍:
git-lfs进程崩溃(SIGSEGV 段错误),报错信息:panic: runtime error: invalid memory address or nil pointer dereference github.com/git-lfs/git-lfs/v3/ssh.(*SSHTransfer).SetConnectionCountAtLeast(...)- GitLab 服务端 pre-receive hook 拦截,即使
git push的对象包(214 个对象)传输成功,但远程 hook 检测到 LFS 对象缺失,拒绝推送:remote: GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".
二、环境上下文
git-lfs版本: 3.7.1(Homebrew 安装),Go 1.25.3 编译- Git 版本: 2.50.1(Apple Git-155)
- 远程仓库:
git@gitlab.xxxx.com:data/data-xxxx.git(内网 GitLab) - LFS 追踪的文件类型:
*.xlsx,*.csv,*.zip,*.rar,*.pptx,*.xls,*.xlsm - 当前分支领先提交: 11 个 commit,涉及 51 个 LFS 对象需要推送
三、探索过程
阶段 1:初步诊断
git status → 工作区干净,领先 origin/wyx 11 个提交
git push → git-lfs 崩溃(SIGSEGV)
尝试禁用 LFS 后推送:
git -c filter.lfs.required=false push --no-verify
→ 代码对象推送成功(214/214),但远程 hook 拒绝:"LFS objects are missing"
阶段 2:修复 SSH 协议崩溃
通过 GIT_TRACE=1 定位崩溃根源:
git-lfs先尝试纯 SSH 协议(git-lfs-transfer命令),GitLab 返回Disallowed command- 回落时
*SSHTransfer对象为 nil,触发 nil pointer dereference
发现额外配置问题: 本地 .git/config 中配置了:
[lfs]
url = ssh://git@gitlab.xxxx.com/data/data-xxxx.git/info/lfs
这个 /info/lfs 后缀是错误的——当 git-lfs 用此 URL 执行 git-lfs-authenticate 时,传递的路径是 /data/data-xxxx.git/info/lfs,GitLab 无法识别,返回 The project you were looking for could not be found。
修复动作:
git config --local --unset lfs.url
git config --local lfs.ssh.autoProtocol false
- 删除
lfs.url让 git-lfs 自动从 remote URL 推导正确路径 autoProtocol false禁用纯 SSH 协议尝试,避免崩溃
阶段 3:git lfs push 卡死
修复后 git lfs push origin wyx 不再崩溃,但卡死在 0% (0/1) 进度。
用 GIT_CURL_VERBOSE=1 GIT_TRACE=1 深入排查,发现:
- SSH 认证成功(
git-lfs-authenticate返回 token) - HTTP batch 请求已发送(
POST /info/lfs/objects/batch) - 请求发出后无响应返回——git-lfs 的 HTTP 客户端挂起
但用 curl 模拟完全相同的请求(含 Accept: application/vnd.git-lfs+json、Content-Type: application/vnd.git-lfs+json、User-Agent 和 Authorization header),63ms 即返回 200 OK。说明:
- 服务端 LFS API 正常工作
- 问题出在
git-lfs二进制本身(Go 1.25.3 运行时的 HTTP 客户端可能有 bug)
阶段 4:手动推送 LFS 对象(解决方案)
绕过损坏的 git-lfs 二进制,直接使用 GitLab LFS HTTP API:
工作流:
- SSH 执行
git-lfs-authenticate获取 Bearer token 和 LFS endpoint URL git lfs push --dry-run获取需要推送的 51 个 OIDPOST /info/lfs/objects/batch获取每个 OID 的上传 URL(含预签名认证)PUT <upload_url>逐个上传文件内容(含 SHA256 校验)
使用 Python 脚本实现,全部 51 个对象上传成功(最大 756KB,总大小约 1.3MB)。
阶段 5:最终推送
LFS 对象上传完成后,禁用 LFS pre-push hook 执行 git push:
git -c filter.lfs.required=false push --no-verify
→ 推送成功:91b76e7d..83d2c9e8 wyx -> wyx
四、根因总结
| 问题 | 根因 |
|---|---|
git-lfs 段错误崩溃 |
git-lfs/3.7.1 用 Go 1.25.3 编译,SSH 协议协商失败后 nil pointer dereference |
LFS 认证失败 project not found |
.git/config 中 lfs.url 配置了错误路径(带 /info/lfs 后缀) |
git lfs push 卡死 |
git-lfs 二进制本身的 HTTP 客户端存在 bug,发出 batch 请求后无法接收响应 |
| 远程 hook 拒绝推送 | LFS 对象未上传到 GitLab 存储 |
五、后续注意点
-
git-lfs二进制损坏:当前系统的git-lfs/3.7.1(Go 1.25.3)有多个 bug。后续建议:- 尝试降级到稳定版本:
brew install git-lfs@3.4或更早版本 - 或等 Homebrew 发布修复版本后升级
- 应急直接使用 Python 脚本通过 API 推送
- 尝试降级到稳定版本:
-
lfs.url配置规范:如果手动配置lfs.url,路径必须是仓库路径本身(data/data-xxxx.git),不要加/info/lfs后缀。或者不设lfs.url,让 git-lfs 自动从 remote URL 推导。 -
LFS 推送替代方案:如果以后
git lfs push又出问题,保留的解决路径:git lfs push --dry-run获取 OID 列表- 通过
git-lfs-authenticate获取 token - 直接调 LFS batch API + PUT 上传
-
git push触发 LFS pre-push hook:在 git-lfs 修复前,推送时需显式禁用 LFS hook:git -c filter.lfs.required=false push --no-verify