我如何使用智能协议(原始)通过http获取git对象? [英] How can I fetch git objects using the smart protocol (raw) over http?
问题描述
我试图通过http使用git smart协议从github.com/git/git获取标签v2.4.2的注释。
//获取refs
curl -HUser- Agent:git / 1.8.1-v https://github.com/git/git/info/refs?service=git-upload-pack
返回参考:
.....
003e2be062dfcfd1fd4aca132ec02a40b56f63776202裁判/标签/ V2.4.1
0041aaa7e0d7f8f003c0c8ab34f959083f6d191d44ca裁判/标签/ V2.4.1 ^ {}
003e29932f3915935d773dc8d52c292cadd81c81071d裁判/标签/ V2.4.2
00419eabf5b536662000f79978c4d1b6e4eff5c8d785裁判/标签/ V2.4.2 ^ {}
//制作上传包请求
printf0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d785\\\
0024have 003e2be062dfcfd1fd4aca132ec02a40b56f63776202\\\
0000| curl -HUser-Agent:git / 1.8.1-v -d @ - https://github.com/git/git/git-upload-pack -HContent-Type:application / x-git- upload-pack-request--trace-ascii / dev / stdout
这不会返回任何结果。我想知道请求中有什么问题(例如,我错误地计算了十六进制吗?)
警告:--trace-ascii覆盖以前的跟踪/详细选项
==信息:在DNS缓存中找不到主机名
==信息:尝试192.30.252.130 ...
==信息:连接到github.com( 192.30.252.130)端口443(#0)
==信息:使用TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
== TLS 1.2连接信息:服务器证书:github.com
==信息:服务器证书:DigiCert SHA2扩展验证服务器CA
==信息:服务器证书:DigiCert高保证EV根CA
=>发送头文件,170字节(0xaa)
0000:POST / git / git / git-upload-pack HTTP / 1.1
0028:Host:github.com
003a:Accept:* / *
0047:User-Agent:git / 1.8.1
005e:Content-Type:application / x-git-upload-pack-request
0093:Content-Length:110
00a8:
=>发送数据,110个字节(0x6e)
0000:0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d7850024包含00
0040:3e2be062dfcfd1fd4aca132ec02a40b56f637762020000
==信息:上传完全发送:110个字节中110个
<= Recv头文件,17字节(0x11)
0000:HTTP / 1.1 200 OK
==信息:服务器GitHub Babel 2.0未列入黑名单
<= Recv头,26字节(0x1a)
0000:服务器:GitHub Babel 2.0
<= Recv标题,52字节(0x34)
0000:Content-Type:application / x-git-upload-pack-result
< ; = Recv头,28字节(0x1c)
0000:传输编码:分块
<= Recv头,40字节(0x28)
0000:到期日:1980年1月1日星期五:00:00 GMT
<= Recv标题,18字节(0x12)
0000:Pragma:no-cache
<= Recv标题,53字节(0x35)
0000:缓存控制:no-cache,max-age = 0,必须重新验证
<= Recv标题,23字节(0x17)
0000:变化:接受编码
< ; = Recv头,2字节(0x2)
0000:
<= Recv数据,5字节(0x5)
0000:0
0003:
==信息:连接#0到主机github.com保持完好
我为什么要这么做?
- 对文件系统有写访问权限
- 避免获取不必要的数据(即提交)
- 标准API /协议
解决方案
提交十六进制
您没有错误计算十六进制,但你没有传递正确的值。请记住,智能协议之前有一个长度计数:
< length>< data>
因此,对于如下所示的行:
00419eabf5b536662000f79978c4d1b6e4eff5c8d785 refs / tags / v2.4.2 ^ {}
你需要丢弃前四个字符,这使得实际提交十六进制:
9eabf5b536662000f79978c4d1b6e4eff5c8d785
请求格式
当
POST
一个请求,有
和想要
行应该用换行符分隔,但如果你看看curl
的输出,你可以看到没有换行符:=>发送数据,110字节(0x6e)
0000:0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d7850024 has 00
0040:3e2be062dfcfd1fd4aca132ec02a40b56f637762020000
您需要使用
- data-binary
而不是- data
:- data-binary @ -
您需要为这些行加上长度计数的前缀,并且您需要以
0000
组成的行结束:0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785
0032have 2be062dfcfd1fd4aca132ec02a40b56f63776202
0000
调试提示
您可以在您的环境中设置
GIT_TRACE_PACKET = 1
来自git
的丰富的调试信息能够准确地查看它来回发送的内容。
这就是他写的 h2>
即使有以上信息,我也无法自己得到回复,但我认为这会有所帮助。
更新
所以,这很有趣。 b
$ b我在本地设置了一个git服务器(使用
git http-backend
和 thttpd ),并运行tcpdump
来获取由git远程更新
操作。事实证明,你需要用一个空命令来分隔want
和有指令,该命令是
0000
(不换行,因为长度也对新行进行编码)。即:
< length> want< commitid>< newline>
0000< length>有< commitid>< newline>
< length>完成
例如:
0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785
00000032have 2be062dfcfd1fd4aca132ec02a40b56f63776202
0009done
这给了我:
0000:POST / git / git / git-upload-pack HTTP / 1.1
0028:Host:github.com
003a:接受:* / *
0047:Content-type:application / x-git-upload-pack-request
007c:User -agent:git / 1.8
0091:Content-Length:113
00a6:
=>发送数据,113字节(0x71)
0000:0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785.00000032需要2
0040:be062dfcfd1fd4aca132ec02a40b56f63776202.0009done。
== Info:上传完全发送:113个字节中的113个
<= Recv头,17个字节(0x11)
0000:HTTP / 1.1 200 OK
< = Recv头,26字节(0x1a)
0000:服务器:GitHub Babel 2.0
<= Recv标头,52字节(0x34)
0000:Content-Type:application / x-git -upload-pack-result
<= Recv头,28字节(0x1c)
0000:传输编码:分块
<= Recv头,40字节(0x28)
0000:到期日:1980年1月1日星期五00:00:00 GMT
<= Recv标题,18字节(0x12)
0000:Pragma:no-cache
<= Recv 53字节(0x35)
0000:缓存控制:no-cache,max-age = 0,必须重新验证
<= Recv头,23字节(0x17)
0000 :Vary:Accept-Encoding
<= Recv头,2字节(0x2)
0000:
<= Recv数据,4字节(0x4)
0000:31
<= Recv data,51字节(0x33)
0000:0031ACK 2be062dfcfd1fd4aca132ec02a40b56f63776202。
<=接收数据,6字节(0x6)
0000:1fff
<=接收数据,1370字节(0x55a)
0000:PACK ...... [.. X ... An.0 ... z.?`..d * .. .. @ ..ž(TU ......>〜乙.....] .8
0040:2 ... j).OQ} ..#............ [.. 8K..t ..,%.S..u。 。@ l..XT ... o ......'...
[....]
双重奖励更新
您可以使用
git unpack-objects
命令提取packfile。正如你从上面的跟踪中看到的,你首先得到一个长度编码的响应(),然后是包数据,所以你需要放弃第一行:
0031ACK 2be062dfcfd1fd4aca132ec02a40b56f63776202
$ git init tmprepo
$ cd temprepo
$ tail -n +2 output_from_curl | git unpack-objects
解包对象:100%(91/91),完成。
$ find .git / objects -type f |头-3
$ git cat-file -p dc940e63c453199dd9a7285533fbf2355bab03d1
/ *
* GIT - 来自地狱的信息管理员
*
*版权所有(C)Linus Torvalds, 2005
*
*这个处理基本的git sha1目标文件 - 打包,解包,
*创建等等
* /
[...]
I'm trying to fetch the annotation of tag "v2.4.2" from github.com/git/git using the git smart protocol over http.
// Get the refs
curl -H "User-Agent: git/1.8.1" -v https://github.com/git/git/info/refs?service=git-upload-pack
Returns the refs:
..... 003e2be062dfcfd1fd4aca132ec02a40b56f63776202 refs/tags/v2.4.1 0041aaa7e0d7f8f003c0c8ab34f959083f6d191d44ca refs/tags/v2.4.1^{} 003e29932f3915935d773dc8d52c292cadd81c81071d refs/tags/v2.4.2 00419eabf5b536662000f79978c4d1b6e4eff5c8d785 refs/tags/v2.4.2^{}
// Make the upload pack request
printf "0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d785\n0024have 003e2be062dfcfd1fd4aca132ec02a40b56f63776202\n0000" | curl -H "User-Agent: git/1.8.1" -v -d @- https://github.com/git/git/git-upload-pack -H "Content-Type: application/x-git-upload-pack-request" --trace-ascii /dev/stdout
This returns nothing. I'm wondering what's wrong in the request (i.e did I miscalculate the hex?)
Warning: --trace-ascii overrides an earlier trace/verbose option == Info: Hostname was NOT found in DNS cache == Info: Trying 192.30.252.130... == Info: Connected to github.com (192.30.252.130) port 443 (#0) == Info: TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 == Info: Server certificate: github.com == Info: Server certificate: DigiCert SHA2 Extended Validation Server CA == Info: Server certificate: DigiCert High Assurance EV Root CA => Send header, 170 bytes (0xaa) 0000: POST /git/git/git-upload-pack HTTP/1.1 0028: Host: github.com 003a: Accept: */* 0047: User-Agent: git/1.8.1 005e: Content-Type: application/x-git-upload-pack-request 0093: Content-Length: 110 00a8: => Send data, 110 bytes (0x6e) 0000: 0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d7850024have 00 0040: 3e2be062dfcfd1fd4aca132ec02a40b56f637762020000 == Info: upload completely sent off: 110 out of 110 bytes <= Recv header, 17 bytes (0x11) 0000: HTTP/1.1 200 OK == Info: Server GitHub Babel 2.0 is not blacklisted <= Recv header, 26 bytes (0x1a) 0000: Server: GitHub Babel 2.0 <= Recv header, 52 bytes (0x34) 0000: Content-Type: application/x-git-upload-pack-result <= Recv header, 28 bytes (0x1c) 0000: Transfer-Encoding: chunked <= Recv header, 40 bytes (0x28) 0000: Expires: Fri, 01 Jan 1980 00:00:00 GMT <= Recv header, 18 bytes (0x12) 0000: Pragma: no-cache <= Recv header, 53 bytes (0x35) 0000: Cache-Control: no-cache, max-age=0, must-revalidate <= Recv header, 23 bytes (0x17) 0000: Vary: Accept-Encoding <= Recv header, 2 bytes (0x2) 0000: <= Recv data, 5 bytes (0x5) 0000: 0 0003: == Info: Connection #0 to host github.com left intact
Why am I trying this?
- I don't have write access to the file system
- Avoid fetching unnecessary data (i.e the commits)
- Standard API/Protocol
Commit hex
You didn't miscalculate the hex, but you're not passing the correct value. Remember that each line in the smart protocol is preceded by a length count:
<length><data>
So for a line that looks like this:
00419eabf5b536662000f79978c4d1b6e4eff5c8d785 refs/tags/v2.4.2^{}
You need to discard the first four characters, which makes the actual commit hex:
9eabf5b536662000f79978c4d1b6e4eff5c8d785
Request format
When POST
ing a request, the have
and want
lines are supposed to be separated by a newline, but if you take a look at the output from curl
, you can see that there is no newline:
=> Send data, 110 bytes (0x6e)
0000: 0031want 00419eabf5b536662000f79978c4d1b6e4eff5c8d7850024have 00
0040: 3e2be062dfcfd1fd4aca132ec02a40b56f637762020000
You need to use --data-binary
instead of --data
:
--data-binary @-
You need to prefix these lines with a length count, and you need to end with a line consisting of 0000
:
0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785
0032have 2be062dfcfd1fd4aca132ec02a40b56f63776202
0000
Debugging tips
You can set GIT_TRACE_PACKET=1
in your environment if you want to get copious debugging information from git
to see exactly what it's sending back and forth.
And that's all he wrote
I'm not able to get a response myself, even given the above information, but I figured it would help.
Update
So, this was fun.
I set up a git server locally (using git http-backend
and thttpd), and ran tcpdump
to grab the traffic generated by a git remote update
operation. It turns out that the you need to separate the want
and have
directives with a null command, which is 0000
(no newline, because the length encodes newlines, too). That is:
<length>want <commitid><newline>
0000<length>have <commitid><newline>
<length>done
E.g:
0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785
00000032have 2be062dfcfd1fd4aca132ec02a40b56f63776202
0009done
That gives me:
0000: POST /git/git/git-upload-pack HTTP/1.1
0028: Host: github.com
003a: Accept: */*
0047: Content-type: application/x-git-upload-pack-request
007c: User-agent: git/1.8
0091: Content-Length: 113
00a6:
=> Send data, 113 bytes (0x71)
0000: 0032want 9eabf5b536662000f79978c4d1b6e4eff5c8d785.00000032have 2
0040: be062dfcfd1fd4aca132ec02a40b56f63776202.0009done.
== Info: upload completely sent off: 113 out of 113 bytes
<= Recv header, 17 bytes (0x11)
0000: HTTP/1.1 200 OK
<= Recv header, 26 bytes (0x1a)
0000: Server: GitHub Babel 2.0
<= Recv header, 52 bytes (0x34)
0000: Content-Type: application/x-git-upload-pack-result
<= Recv header, 28 bytes (0x1c)
0000: Transfer-Encoding: chunked
<= Recv header, 40 bytes (0x28)
0000: Expires: Fri, 01 Jan 1980 00:00:00 GMT
<= Recv header, 18 bytes (0x12)
0000: Pragma: no-cache
<= Recv header, 53 bytes (0x35)
0000: Cache-Control: no-cache, max-age=0, must-revalidate
<= Recv header, 23 bytes (0x17)
0000: Vary: Accept-Encoding
<= Recv header, 2 bytes (0x2)
0000:
<= Recv data, 4 bytes (0x4)
0000: 31
<= Recv data, 51 bytes (0x33)
0000: 0031ACK 2be062dfcfd1fd4aca132ec02a40b56f63776202.
<= Recv data, 6 bytes (0x6)
0000: 1fff
<= Recv data, 1370 bytes (0x55a)
0000: PACK.......[..x...An.0...z.?`..d.*..@..z..(.tu......>~B.....]..8
0040: 2...j).OQ}..#.....'......[..8K..t..,%.S..u..@l..XT...o......'...
[....]
Double-bonus update
You can use the git unpack-objects
command to extract the packfile. As you can see from the above trace, you first get back a length-encoded response (
0031ACK 2be062dfcfd1fd4aca132ec02a40b56f63776202
) followed by the pack data, so you need to discard that first line:
$ git init tmprepo
$ cd temprepo
$ tail -n +2 output_from_curl | git unpack-objects
Unpacking objects: 100% (91/91), done.
$ find .git/objects -type f | head -3
$ git cat-file -p dc940e63c453199dd9a7285533fbf2355bab03d1
/*
* GIT - The information manager from hell
*
* Copyright (C) Linus Torvalds, 2005
*
* This handles basic git sha1 object files - packing, unpacking,
* creation etc.
*/
[...]
这篇关于我如何使用智能协议(原始)通过http获取git对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!