Skip to content

Commit 835fe09

Browse files
committed
Merge branch 'bw/protocol-v1' into next
A new mechanism to upgrade the wire protocol in place is proposed and demonstrated that it works with the older versions of Git without harming them. * bw/protocol-v1: Documentation: document Extra Parameters ssh: introduce a 'simple' ssh variant i5700: add interop test for protocol transition http: tell server that the client understands v1 connect: tell server that the client understands v1 connect: teach client to recognize v1 server response upload-pack, receive-pack: introduce protocol version 1 daemon: recognize hidden request arguments protocol: introduce protocol extension mechanisms pkt-line: add packet_write function connect: in ref advertisement, shallows are last
2 parents ef8aa26 + 6464679 commit 835fe09

19 files changed

+968
-148
lines changed

Documentation/config.txt

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,12 +2094,31 @@ ssh.variant::
20942094
Depending on the value of the environment variables `GIT_SSH` or
20952095
`GIT_SSH_COMMAND`, or the config setting `core.sshCommand`, Git
20962096
auto-detects whether to adjust its command-line parameters for use
2097-
with plink or tortoiseplink, as opposed to the default (OpenSSH).
2097+
with ssh (OpenSSH), plink or tortoiseplink, as opposed to the default
2098+
(simple).
20982099
+
20992100
The config variable `ssh.variant` can be set to override this auto-detection;
2100-
valid values are `ssh`, `plink`, `putty` or `tortoiseplink`. Any other value
2101-
will be treated as normal ssh. This setting can be overridden via the
2102-
environment variable `GIT_SSH_VARIANT`.
2101+
valid values are `ssh`, `simple`, `plink`, `putty` or `tortoiseplink`. Any
2102+
other value will be treated as normal ssh. This setting can be overridden via
2103+
the environment variable `GIT_SSH_VARIANT`.
2104+
+
2105+
The current command-line parameters used for each variant are as
2106+
follows:
2107+
+
2108+
--
2109+
2110+
* `ssh` - [-p port] [-4] [-6] [-o option] [username@]host command
2111+
2112+
* `simple` - [username@]host command
2113+
2114+
* `plink` or `putty` - [-P port] [-4] [-6] [username@]host command
2115+
2116+
* `tortoiseplink` - [-P port] [-4] [-6] -batch [username@]host command
2117+
2118+
--
2119+
+
2120+
Except for the `simple` variant, command-line parameters are likely to
2121+
change as git gains new features.
21032122

21042123
i18n.commitEncoding::
21052124
Character encoding the commit messages are stored in; Git itself
@@ -2527,6 +2546,23 @@ The protocol names currently used by git are:
25272546
`hg` to allow the `git-remote-hg` helper)
25282547
--
25292548

2549+
protocol.version::
2550+
Experimental. If set, clients will attempt to communicate with a
2551+
server using the specified protocol version. If unset, no
2552+
attempt will be made by the client to communicate using a
2553+
particular protocol version, this results in protocol version 0
2554+
being used.
2555+
Supported versions:
2556+
+
2557+
--
2558+
2559+
* `0` - the original wire protocol.
2560+
2561+
* `1` - the original wire protocol with the addition of a version string
2562+
in the initial response from the server.
2563+
2564+
--
2565+
25302566
pull.ff::
25312567
By default, Git does not create an extra merge commit when merging
25322568
a commit that is a descendant of the current commit. Instead, the

Documentation/git.txt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,10 @@ other
522522
If either of these environment variables is set then 'git fetch'
523523
and 'git push' will use the specified command instead of 'ssh'
524524
when they need to connect to a remote system.
525-
The command will be given exactly two or four arguments: the
526-
'username@host' (or just 'host') from the URL and the shell
527-
command to execute on that remote system, optionally preceded by
528-
`-p` (literally) and the 'port' from the URL when it specifies
529-
something other than the default SSH port.
525+
The command-line parameters passed to the configured command are
526+
determined by the ssh variant. See `ssh.variant` option in
527+
linkgit:git-config[1] for details.
528+
530529
+
531530
`$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
532531
by the shell, which allows additional arguments to be included.
@@ -701,6 +700,7 @@ of clones and fetches.
701700
which feed potentially-untrusted URLS to git commands. See
702701
linkgit:git-config[1] for more details.
703702

703+
704704
`GIT_OPTIONAL_LOCKS`::
705705
If set to `0`, Git will complete any requested operation without
706706
performing any optional sub-operations that require taking a lock.
@@ -709,6 +709,12 @@ of clones and fetches.
709709
the background which do not want to cause lock contention with
710710
other operations on the repository. Defaults to `1`.
711711

712+
`GIT_PROTOCOL`::
713+
For internal use only. Used in handshaking the wire protocol.
714+
Contains a colon ':' separated list of keys with optional values
715+
'key[=value]'. Presence of unknown keys and values must be
716+
ignored.
717+
712718
Discussion[[Discussion]]
713719
------------------------
714720

Documentation/technical/http-protocol.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ smart server reply:
219219
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
220220
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
221221

222+
The client may send Extra Parameters (see
223+
Documentation/technical/pack-protocol.txt) as a colon-separated string
224+
in the Git-Protocol HTTP header.
225+
222226
Dumb Server Response
223227
^^^^^^^^^^^^^^^^^^^^
224228
Dumb servers MUST respond with the dumb server reply format.
@@ -269,7 +273,11 @@ the C locale ordering. The stream SHOULD include the default ref
269273
named `HEAD` as the first ref. The stream MUST include capability
270274
declarations behind a NUL on the first ref.
271275

276+
The returned response contains "version 1" if "version=1" was sent as an
277+
Extra Parameter.
278+
272279
smart_reply = PKT-LINE("# service=$servicename" LF)
280+
*1("version 1")
273281
ref_list
274282
"0000"
275283
ref_list = empty_list / non_empty_list

Documentation/technical/pack-protocol.txt

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,45 @@ communicates with that invoked process over the SSH connection.
3939
The file:// transport runs the 'upload-pack' or 'receive-pack'
4040
process locally and communicates with it over a pipe.
4141

42+
Extra Parameters
43+
----------------
44+
45+
The protocol provides a mechanism in which clients can send additional
46+
information in its first message to the server. These are called "Extra
47+
Parameters", and are supported by the Git, SSH, and HTTP protocols.
48+
49+
Each Extra Parameter takes the form of `<key>=<value>` or `<key>`.
50+
51+
Servers that receive any such Extra Parameters MUST ignore all
52+
unrecognized keys. Currently, the only Extra Parameter recognized is
53+
"version=1".
54+
4255
Git Transport
4356
-------------
4457

4558
The Git transport starts off by sending the command and repository
4659
on the wire using the pkt-line format, followed by a NUL byte and a
4760
hostname parameter, terminated by a NUL byte.
4861

49-
0032git-upload-pack /project.git\0host=myserver.com\0
62+
0033git-upload-pack /project.git\0host=myserver.com\0
63+
64+
The transport may send Extra Parameters by adding an additional NUL
65+
byte, and then adding one or more NUL-terminated strings:
66+
67+
003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0
5068

5169
--
52-
git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
70+
git-proto-request = request-command SP pathname NUL
71+
[ host-parameter NUL ] [ NUL extra-parameters ]
5372
request-command = "git-upload-pack" / "git-receive-pack" /
5473
"git-upload-archive" ; case sensitive
5574
pathname = *( %x01-ff ) ; exclude NUL
5675
host-parameter = "host=" hostname [ ":" port ]
76+
extra-parameters = 1*extra-parameter
77+
extra-parameter = 1*( %x01-ff ) NUL
5778
--
5879

59-
Only host-parameter is allowed in the git-proto-request. Clients
60-
MUST NOT attempt to send additional parameters. It is used for the
80+
host-parameter is used for the
6181
git-daemon name based virtual hosting. See --interpolated-path
6282
option to git daemon, with the %H/%CH format characters.
6383

@@ -117,6 +137,12 @@ we execute it without the leading '/'.
117137
v
118138
ssh [email protected] "git-upload-pack '~alice/project.git'"
119139

140+
Depending on the value of the `protocol.version` configuration variable,
141+
Git may attempt to send Extra Parameters as a colon-separated string in
142+
the GIT_PROTOCOL environment variable. This is done only if
143+
the `ssh.variant` configuration variable indicates that the ssh command
144+
supports passing environment variables as an argument.
145+
120146
A few things to remember here:
121147

122148
- The "command name" is spelled with dash (e.g. git-upload-pack), but
@@ -137,11 +163,13 @@ Reference Discovery
137163
-------------------
138164

139165
When the client initially connects the server will immediately respond
140-
with a listing of each reference it has (all branches and tags) along
166+
with a version number (if "version=1" is sent as an Extra Parameter),
167+
and a listing of each reference it has (all branches and tags) along
141168
with the object name that each reference currently points to.
142169

143-
$ echo -e -n "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
170+
$ echo -e -n "0044git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
144171
nc -v example.com 9418
172+
000aversion 1
145173
00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
146174
side-band side-band-64k ofs-delta shallow no-progress include-tag
147175
00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
@@ -165,7 +193,8 @@ immediately after the ref itself, if presented. A conforming server
165193
MUST peel the ref if it's an annotated tag.
166194

167195
----
168-
advertised-refs = (no-refs / list-of-refs)
196+
advertised-refs = *1("version 1")
197+
(no-refs / list-of-refs)
169198
*shallow
170199
flush-pkt
171200

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ LIB_OBJS += pretty.o
849849
LIB_OBJS += prio-queue.o
850850
LIB_OBJS += progress.o
851851
LIB_OBJS += prompt.o
852+
LIB_OBJS += protocol.o
852853
LIB_OBJS += quote.o
853854
LIB_OBJS += reachable.o
854855
LIB_OBJS += read-cache.o

builtin/receive-pack.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "tmp-objdir.h"
2525
#include "oidset.h"
2626
#include "packfile.h"
27+
#include "protocol.h"
2728

2829
static const char * const receive_pack_usage[] = {
2930
N_("git receive-pack <git-dir>"),
@@ -1961,6 +1962,22 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
19611962
else if (0 <= receive_unpack_limit)
19621963
unpack_limit = receive_unpack_limit;
19631964

1965+
switch (determine_protocol_version_server()) {
1966+
case protocol_v1:
1967+
/*
1968+
* v1 is just the original protocol with a version string,
1969+
* so just fall through after writing the version string.
1970+
*/
1971+
if (advertise_refs || !stateless_rpc)
1972+
packet_write_fmt(1, "version 1\n");
1973+
1974+
/* fallthrough */
1975+
case protocol_v0:
1976+
break;
1977+
case protocol_unknown_version:
1978+
BUG("unknown protocol version");
1979+
}
1980+
19641981
if (advertise_refs || !stateless_rpc) {
19651982
write_head_info();
19661983
}

cache.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,16 @@ static inline enum object_type object_type(unsigned int mode)
449449
#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
450450
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
451451

452+
/*
453+
* Environment variable used in handshaking the wire protocol.
454+
* Contains a colon ':' separated list of keys with optional values
455+
* 'key[=value]'. Presence of unknown keys and values must be
456+
* ignored.
457+
*/
458+
#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
459+
/* HTTP header used to handshake the wire protocol */
460+
#define GIT_PROTOCOL_HEADER "Git-Protocol"
461+
452462
/*
453463
* This environment variable is expected to contain a boolean indicating
454464
* whether we should or should not treat:

0 commit comments

Comments
 (0)