All of lore.kernel.org
 help / color / mirror / Atom feed
* Git Push Always uses Protocol Version 0
@ 2024-01-22  8:59 Zsolt Imre
  2024-01-22 18:52 ` Junio C Hamano
  0 siblings, 1 reply; 4+ messages in thread
From: Zsolt Imre @ 2024-01-22  8:59 UTC (permalink / raw)
  To: git

Hi there,

I'm not entirely sure if this is a bug or I am missing something, but I thought I would share in the hope someone can help out. I'm playing around with Git and trying to implement a git server that communicates over HTTP and supports Git protocol version 2 *only*.

When I `clone` a repository, the Git client (version 2.43.0), after fetching the capabilities using protocol version 2, it proceeds to fetch the refs, again, via protocol version 2 using the `ls-refs` command.  However, when I try to `push` my changes to the repo, the Git client refuses to use protocol version 2 and tries to obtain the ref list using protocol version 0, even if I pass in the `-c protocol.version=2` command line argument.

Is there a way to make the client use only protocol version 2 instead of mixing the different protocols?

Thanks in advance for any help/guidance.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Git Push Always uses Protocol Version 0
  2024-01-22  8:59 Git Push Always uses Protocol Version 0 Zsolt Imre
@ 2024-01-22 18:52 ` Junio C Hamano
  2024-01-22 19:24   ` Zsolt Imre
  0 siblings, 1 reply; 4+ messages in thread
From: Junio C Hamano @ 2024-01-22 18:52 UTC (permalink / raw)
  To: Zsolt Imre; +Cc: git

Zsolt Imre <imrexzsolt@gmail.com> writes:

> I'm not entirely sure if this is a bug or I am missing something,
> but I thought I would share in the hope someone can help out. I'm
> playing around with Git and trying to implement a git server that
> communicates over HTTP and supports Git protocol version 2 *only*.
>
> When I `clone` a repository, the Git client (version 2.43.0),
> after fetching the capabilities using protocol version 2, it
> proceeds to fetch the refs, again, via protocol version 2 using
> the `ls-refs` command.  However, when I try to `push` my changes
> to the repo, the Git client refuses to use protocol version 2 and
> tries to obtain the ref list using protocol version 0, even if I
> pass in the `-c protocol.version=2` command line argument.

Given that v0 and v1 in the push direction behave exactly the same,
and there has been no need to add features that were not supportable
in v1 in the push direction, it is not surprising to see this code

        int cmd_send_pack(int argc, const char **argv, const char *prefix)
        {
		...
                switch (discover_version(&reader)) {
                case protocol_v2:
                        die("support for protocol v2 not implemented yet");
                        break;

in https://github.com/git/git/blob/master/builtin/send-pack.c#L282
and also

        int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        {
		...
                switch (determine_protocol_version_server()) {
                case protocol_v2:
                        /*
                         * push support for protocol v2 has not been implemented yet,
                         * so ignore the request to use v2 and fallback to using v0.
                         */
                        break;

in https://github.com/git/git/blob/master/builtin/receive-pack.c#L2538

that tells the receiving end to demote "v2" request down to "v0",
and have the pushing end honor that choice.

What specifically did you want to gain by using protocol version 2
in the "push" direction that you cannot do with the current
versions?



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Git Push Always uses Protocol Version 0
  2024-01-22 18:52 ` Junio C Hamano
@ 2024-01-22 19:24   ` Zsolt Imre
  2024-01-22 22:04     ` Jeff King
  0 siblings, 1 reply; 4+ messages in thread
From: Zsolt Imre @ 2024-01-22 19:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hi. Thanks for your response. Yes, I saw those switch statements, but probably misunderstood the intent behind them.

Checking `determine_protocol_version_server` the in-code documentation says:

* Used by a server to determine which protocol version should be used based on
* a client's request, communicated via the 'GIT_PROTOCOL' environment variable

I explicitly set the `GIT_PROTOCOL` environment variable to `version=2`. (Will share more at the end of this email why, as you asked anyways)

The client-side calls `discover_version` to check the version supported by the server. Which ultimately ends up being done as:


enum protocol_version determine_protocol_version_client(const char *server_response)
{
enum protocol_version version = protocol_v0;

if (skip_prefix(server_response, "version ", &server_response)) {
version = parse_protocol_version(server_response);

if (version == protocol_unknown_version)
die("server is speaking an unknown protocol");
if (version == protocol_v0)
die("protocol error: server explicitly said version 0");
}

return version;
}

The server, according to my understanding of the documentations so far, will not return a version identifier if the client is not talking the version 2 (or maybe even version 1) of the protocol. 
The git clone I mentioned in my previous email was clearly using protocol version 2 and it set the appropriate header to indicate this when discovering capabilities. See full request headers below.

POST /testing.git/git-upload-pack HTTP/1.1
Host: 127.0.0.1:9000
Accept: application/x-git-upload-pack-result
Accept-Encoding: deflate, gzip
Accept-Language: en-GB, *;q=0.9
Content-Length: 122
Content-Type: application/x-git-upload-pack-request
Git-Protocol: version=2
User-Agent: git/2.43.0

The server, in this case did not return a version identifier as the first PKT-LINE either, but responded otherwise according to the V2 protocol. Everything was working well.

Then, the above request was followed by by a proper fetch command in which the client again specified the use of V2 protocol:

POST /testing.git/git-upload-pack HTTP/1.1
Host: 127.0.0.1:9000
Accept: application/x-git-upload-pack-result
Accept-Encoding: deflate, gzip
Accept-Language: en-GB, *;q=0.9
Content-Length: 160
Content-Type: application/x-git-upload-pack-request
Git-Protocol: version=2
User-Agent: git/2.43.0

Accordingly, the cloning worked perfectly fine.

But then, when I want to push to the repo, the client does not do any capabilities or version discovery, just goes with V0 of the protocol to get the refs:

GET /testing.git/info/refs?service=git-receive-pack HTTP/1.1
Host: 127.0.0.1:9000
Accept: */*
Accept-Encoding: deflate, gzip
Accept-Language: en-GB, *;q=0.9
Cache-Control: no-cache
Pragma: no-cache
User-Agent: git/2.43.0

What I was expecting, given things are going stateless, that on push the client first discovers the protocol supported by the server and picks the most recent - in this case, that would be version 2.

And to answer your question of what I cannot do with the "current versions" of the protocol: I could do everything, of course. But, if there's protocol 0, 1 and 2 and I wanted to implement only version 2, I thought I should be able to. If protocol V2 was complete, I would not have to worry about implementing V0 and V1 (saving some time and headache), especially because I do not care about supporting old clients. I may have misunderstood the word "version" and version 2 is more of an "extension" to V1?


> On 22 Jan 2024, at 18:52, Junio C Hamano <gitster@pobox.com> wrote:
> 
> Zsolt Imre <imrexzsolt@gmail.com> writes:
> 
>> I'm not entirely sure if this is a bug or I am missing something,
>> but I thought I would share in the hope someone can help out. I'm
>> playing around with Git and trying to implement a git server that
>> communicates over HTTP and supports Git protocol version 2 *only*.
>> 
>> When I `clone` a repository, the Git client (version 2.43.0),
>> after fetching the capabilities using protocol version 2, it
>> proceeds to fetch the refs, again, via protocol version 2 using
>> the `ls-refs` command.  However, when I try to `push` my changes
>> to the repo, the Git client refuses to use protocol version 2 and
>> tries to obtain the ref list using protocol version 0, even if I
>> pass in the `-c protocol.version=2` command line argument.
> 
> Given that v0 and v1 in the push direction behave exactly the same,
> and there has been no need to add features that were not supportable
> in v1 in the push direction, it is not surprising to see this code
> 
>        int cmd_send_pack(int argc, const char **argv, const char *prefix)
>        {
> ...
>                switch (discover_version(&reader)) {
>                case protocol_v2:
>                        die("support for protocol v2 not implemented yet");
>                        break;
> 
> in https://github.com/git/git/blob/master/builtin/send-pack.c#L282
> and also
> 
>        int cmd_receive_pack(int argc, const char **argv, const char *prefix)
>        {
> ...
>                switch (determine_protocol_version_server()) {
>                case protocol_v2:
>                        /*
>                         * push support for protocol v2 has not been implemented yet,
>                         * so ignore the request to use v2 and fallback to using v0.
>                         */
>                        break;
> 
> in https://github.com/git/git/blob/master/builtin/receive-pack.c#L2538
> 
> that tells the receiving end to demote "v2" request down to "v0",
> and have the pushing end honor that choice.
> 
> What specifically did you want to gain by using protocol version 2
> in the "push" direction that you cannot do with the current
> versions?
> 
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Git Push Always uses Protocol Version 0
  2024-01-22 19:24   ` Zsolt Imre
@ 2024-01-22 22:04     ` Jeff King
  0 siblings, 0 replies; 4+ messages in thread
From: Jeff King @ 2024-01-22 22:04 UTC (permalink / raw)
  To: Zsolt Imre; +Cc: Junio C Hamano, git

On Mon, Jan 22, 2024 at 07:24:53PM +0000, Zsolt Imre wrote:

> And to answer your question of what I cannot do with the "current
> versions" of the protocol: I could do everything, of course. But, if
> there's protocol 0, 1 and 2 and I wanted to implement only version 2,
> I thought I should be able to. If protocol V2 was complete, I would
> not have to worry about implementing V0 and V1 (saving some time and
> headache), especially because I do not care about supporting old
> clients. I may have misunderstood the word "version" and version 2 is
> more of an "extension" to V1?

I think the main confusion is that there simply isn't a "v2" push
protocol. It has not yet been written.

There was discussion when v2 was being worked on there that might be a
single "git serve" endpoint that would handle both fetch and push. But
in practice the backwards-compatibility technique we use requires asking
for the usual "upload-pack" or "receive-pack". And hence there isn't
really a single protocol, but still a fetch protocol which can be v0 or
v2, and a push protocol which is always v0.

It's possible we'd shift direction there, but IMHO there's value in
having separate per-operation endpoints. There's some more discussion
in this sub-thread:

  https://lore.kernel.org/git/20181213195305.249059-1-jonathantanmy@google.com/

Now of course a v2 push protocol, if it is ever written, will probably
look a lot like the v2 fetch protocol, and they can probably share a lot
of the implementation. But v0 and v2 are not that different either. In a
hypothetical world where v2 push existed and you could get away with
skipping v0 push entirely, I'd expect that "v2 push and v2 fetch" would
be about the same amount of work as the current "v0 push and v2 fetch".

-Peff

PS I saw some mention of "v1" in this thread; I wasn't sure if this was
   meant to refer to "v0" (a mistake I have made lots of times myself).
   But if not, "v1" is not really of any interest. It was a brief
   experimental phase for the client-upgrade mechanisms, and it behaves
   exactly like v0. No version of Git has ever used it by default.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-01-22 22:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-22  8:59 Git Push Always uses Protocol Version 0 Zsolt Imre
2024-01-22 18:52 ` Junio C Hamano
2024-01-22 19:24   ` Zsolt Imre
2024-01-22 22:04     ` Jeff King

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.