如何仅使用curl向Git仓库推送commit?
你当前命令失效的核心原因
- 你存储的
raw_pack文件混入了Wireshark抓取的TCP头、HTTP头、报文分段冗余数据,不是Git协议要求的纯请求二进制内容,服务器无法解析会直接丢弃。 - 请求路径缺失仓库的实际挂载路径,标准路由格式为
<服务器根地址>/<对应仓库的完整路径>.git/git-receive-pack,路由不匹配时服务器不会返回任何内容。 - 缺失Git Smart协议要求的前置引用协商步骤,服务器不会默认进入接收pack文件的状态。
- 使用
-d参数传输二进制pack内容,会触发curl的换行符转换逻辑,损坏pack的二进制结构。
纯curl实现POST推送的完整可执行流程
第一步:完成前置引用协商
Git的HTTP推送是两阶段交互,必须先完成协商才能进入接收状态,执行以下命令获取服务器的引用列表和支持的能力:
curl -X POST "http://<你的服务器地址>/<仓库路径>.git/git-receive-pack" \ -H "Content-Type: application/x-git-receive-pack-request" \ -H "Accept: application/x-git-receive-pack-result" \ -u "你的用户名:对应密码" \ --data ""
- 该请求返回的是pkt-line格式的内容,包含服务器当前所有分支的commit hash、支持的推送能力列表,这部分内容是后续构造请求体的必需依据。
- 如果没有返回正常的pkt-line内容,先核对路径、认证信息,解决路由和权限问题再继续。
第二步:构造符合协议要求的推送请求体
不要直接使用原始抓包的报文文件,请求体由三部分二进制内容拼接而成:
- pkt-line格式的引用更新声明
- 每行内容前加4位十六进制长度头,计算规则为该行总字节数(包含长度头本身)的十六进制值。
- 第一行内容格式为:
<旧引用hash(新建分支填40个0)> <新生成的目标commit hash> 远端要更新的引用路径(如refs/heads/main)\0 带过来的服务器支持的能力列表
- 纯pack二进制内容
从Wireshark抓包中提取纯pack的二进制数据,剔除TCP、IP、以太网帧头和HTTP头的冗余部分,这部分就是你之前生成的可被Git识别的pack文件内容。 - 结束分隔标记
在请求体最后加上固定的pkt-line结束标记0000。
- 将以上三部分按顺序拼接为单独的二进制文件
push_body.bin,注意不要修改二进制内容的字节顺序。
第三步:发送正式推送请求
必须使用--data-binary参数传输二进制内容,避免curl对二进制流做格式转换:
curl -X POST "http://<你的服务器地址>/<仓库路径>.git/git-receive-pack" \ -H "Content-Type: application/x-git-receive-pack-request" \ -H "Accept: application/x-git-receive-pack-result" \ -u "你的用户名:对应密码" \ --data-binary "@push_body.bin"
- 服务器处理完成后会返回pkt-line格式的结果,明确标注本次推送的引用更新是否成功。
- 可直接登录服务器查看对应仓库的提交记录,验证文件是否正常生成。
常见无响应问题排查
- 给curl命令加
-v参数打印完整交互日志,根据HTTP状态码定位问题:404为路径错误、403为认证失败、200但解析失败为请求体构造错误。 - 检查pkt-line的长度头计算是否正确,长度值错误会导致服务器直接截断报文,不会给出错误响应。
- 确认没有跳过前置的协商请求,Smart协议的有状态交互要求必须完成协商步骤才能接收pack内容。
内容的提问来源于stack exchange,提问作者NoOneIsHere
相关产品推荐
相关产品推荐

