diff options
authorJunio C Hamano <>2021-09-23 20:44:47 (GMT)
committerJunio C Hamano <>2021-09-23 20:44:47 (GMT)
commitcabb41d0f6c93077229502e7c2d57397808393c8 (patch)
parentb5866edf97c19bea2b0557beeaec4223ad54e202 (diff)
parent1b421e7a5aa6984777029ab799f9a0221875e1dd (diff)
Merge branch 'jk/http-server-protocol-versions'
Taking advantage of the CGI interface, http-backend has been updated to enable protocol v2 automatically when the other side asks for it. * jk/http-server-protocol-versions: docs/protocol-v2: point readers transport config discussion docs/git: discuss server-side config for GIT_PROTOCOL docs/http-backend: mention v2 protocol http-backend: handle HTTP_GIT_PROTOCOL CGI variable t5551: test v2-to-v0 http protocol fallback
7 files changed, 73 insertions, 4 deletions
diff --git a/Documentation/git-http-backend.txt b/Documentation/git-http-backend.txt
index 558966a..0c5c0dd 100644
--- a/Documentation/git-http-backend.txt
+++ b/Documentation/git-http-backend.txt
@@ -16,7 +16,9 @@ A simple CGI program to serve the contents of a Git repository to Git
clients accessing the repository over http:// and https:// protocols.
The program supports clients fetching using both the smart HTTP protocol
and the backwards-compatible dumb HTTP protocol, as well as clients
-pushing using the smart HTTP protocol.
+pushing using the smart HTTP protocol. It also supports Git's
+more-efficient "v2" protocol if properly configured; see the
+discussion of `GIT_PROTOCOL` in the ENVIRONMENT section below.
It verifies that the directory has the magic file
"git-daemon-export-ok", and it will refuse to export any Git directory
@@ -77,6 +79,18 @@ Apache 2.x::
SetEnv GIT_PROJECT_ROOT /var/www/git
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
+# This is not strictly necessary using Apache and a modern version of
+# git-http-backend, as the webserver will pass along the header in the
+# environment as HTTP_GIT_PROTOCOL, and http-backend will copy that into
+# GIT_PROTOCOL. But you may need this line (or something similar if you
+# are using a different webserver), or if you want to support older Git
+# versions that did not do that copying.
+# Having the webserver set up GIT_PROTOCOL is perfectly fine even with
+# modern versions (and will take precedence over HTTP_GIT_PROTOCOL,
+# which means it can be used to override the client's request).
+SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
To enable anonymous read access but authenticated write access,
@@ -264,6 +278,16 @@ a repository with an extremely large number of refs. The value can be
specified with a unit (e.g., `100M` for 100 megabytes). The default is
10 megabytes.
+Clients may probe for optional protocol capabilities (like the v2
+protocol) using the `Git-Protocol` HTTP header. In order to support
+these, the contents of that header must appear in the `GIT_PROTOCOL`
+environment variable. Most webservers will pass this header to the CGI
+via the `HTTP_GIT_PROTOCOL` variable, and `git-http-backend` will
+automatically copy that to `GIT_PROTOCOL`. However, some webservers may
+be more selective about which headers they'll pass, in which case they
+need to be configured explicitly (see the mention of `Git-Protocol` in
+the Apache config from the earlier EXAMPLES section).
The backend process sets GIT_COMMITTER_NAME to '$REMOTE_USER' and
ensuring that any reflogs created by 'git-receive-pack' contain some
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index 739416e..8f87b23 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -48,6 +48,14 @@ OPTIONS
The repository to sync from.
+ Internal variable used for handshaking the wire protocol. Server
+ admins may need to configure some transports to allow this
+ variable to be passed. See the discussion in linkgit:git[1].
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 6dd241e..e4b8259 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -894,6 +894,21 @@ for full details.
Contains a colon ':' separated list of keys with optional values
'key[=value]'. Presence of unknown keys and values must be
+Note that servers may need to be configured to allow this variable to
+pass over some transports. It will be propagated automatically when
+accessing local repositories (i.e., `file://` or a filesystem path), as
+well as over the `git://` protocol. For git-over-http, it should work
+automatically in most configurations, but see the discussion in
+linkgit:git-http-backend[1]. For git-over-ssh, the ssh server may need
+to be configured to allow clients to pass this variable (e.g., by using
+`AcceptEnv GIT_PROTOCOL` with OpenSSH).
+This configuration is optional. If the variable is not propagated, then
+clients will fall back to the original "v0" protocol (but may miss out
+on some performance improvements or features). This variable currently
+only affects clones and fetches; it is not yet used for pushes (but may
+be in the future).
If set to `0`, Git will complete any requested operation without
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 213538f..59b86fc 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -42,7 +42,8 @@ Initial Client Request
In general a client can request to speak protocol v2 by sending
`version=2` through the respective side-channel for the transport being
used which inevitably sets `GIT_PROTOCOL`. More information can be
-found in `pack-protocol.txt` and `http-protocol.txt`. In all cases the
+found in `pack-protocol.txt` and `http-protocol.txt`, as well as the
+`GIT_PROTOCOL` definition in `git.txt`. In all cases the
response from the server is the capability advertisement.
Git Transport
@@ -58,6 +59,8 @@ SSH and File Transport
When using either the ssh:// or file:// transport, the GIT_PROTOCOL
environment variable must be set explicitly to include "version=2".
+The server may need to be configured to allow this environment variable
+to pass.
HTTP Transport
@@ -84,6 +87,9 @@ Subsequent requests are then made directly to the service
Uses the `--http-backend-info-refs` option to
+The server may need to be configured to pass this header's contents via
+the `GIT_PROTOCOL` variable. See the discussion in `git-http-backend.txt`.
Capability Advertisement
diff --git a/http-backend.c b/http-backend.c
index 838374e..e7c0eea 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -739,6 +739,7 @@ static int bad_request(struct strbuf *hdr, const struct service_cmd *c)
int cmd_main(int argc, const char **argv)
char *method = getenv("REQUEST_METHOD");
+ const char *proto_header;
char *dir;
struct service_cmd *cmd = NULL;
char *cmd_arg = NULL;
@@ -789,6 +790,9 @@ int cmd_main(int argc, const char **argv)
max_request_buffer = git_env_ulong("GIT_HTTP_MAX_REQUEST_BUFFER",
+ proto_header = getenv("HTTP_GIT_PROTOCOL");
+ if (proto_header)
+ setenv(GIT_PROTOCOL_ENVIRONMENT, proto_header, 0);
cmd->imp(&hdr, cmd_arg);
return 0;
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index afa91e3..180a41f 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -81,8 +81,6 @@ PassEnv GIT_TRACE
-SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
@@ -117,6 +115,11 @@ Alias /auth/dumb/ www/auth/dumb/
+<LocationMatch /smart_v0/>
ScriptAlias /smart/incomplete_length/git-upload-pack
ScriptAlias /smart/incomplete_body/git-upload-pack
ScriptAliasMatch /error_git_upload_pack/(.*)/git-upload-pack
diff --git a/t/ b/t/
index 4f87d90..cffc47a 100755
--- a/t/
+++ b/t/
@@ -558,4 +558,13 @@ test_expect_success 'http auth forgets bogus credentials' '
expect_askpass both user@host
+test_expect_success 'client falls back from v2 to v0 to match server' '
+ git clone $HTTPD_URL/smart_v0/repo.git repo-v0 &&
+ # check for v0; there the HEAD symref is communicated in the capability
+ # line; v2 uses a different syntax on each ref advertisement line
+ grep symref=HEAD:refs/heads/ trace