git@vger.kernel.org mailing list mirror (one of many)
 help / Atom feed
From: Derrick Stolee <stolee@gmail.com>
To: Brandon Williams <bmwill@google.com>, git@vger.kernel.org
Cc: sbeller@google.com, gitster@pobox.com, peff@peff.net,
	philipoakley@iee.org, jrnieder@gmail.com
Subject: Re: [PATCH v2 12/27] serve: introduce git-serve
Date: Wed, 31 Jan 2018 10:39:59 -0500
Message-ID: <a9500d32-3f0a-4979-dcde-fb2acf0b3434@gmail.com> (raw)
In-Reply-To: <20180125235838.138135-13-bmwill@google.com>

On 1/25/2018 6:58 PM, Brandon Williams wrote:
> Introduce git-serve, the base server for protocol version 2.
>
> Protocol version 2 is intended to be a replacement for Git's current
> wire protocol.  The intention is that it will be a simpler, less
> wasteful protocol which can evolve over time.
>
> Protocol version 2 improves upon version 1 by eliminating the initial
> ref advertisement.  In its place a server will export a list of
> capabilities and commands which it supports in a capability
> advertisement.  A client can then request that a particular command be
> executed by providing a number of capabilities and command specific
> parameters.  At the completion of a command, a client can request that
> another command be executed or can terminate the connection by sending a
> flush packet.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
>   .gitignore                              |   1 +
>   Documentation/technical/protocol-v2.txt | 117 +++++++++++++++
>   Makefile                                |   2 +
>   builtin.h                               |   1 +
>   builtin/serve.c                         |  30 ++++
>   git.c                                   |   1 +
>   serve.c                                 | 249 ++++++++++++++++++++++++++++++++
>   serve.h                                 |  15 ++
>   t/t5701-git-serve.sh                    |  56 +++++++
>   9 files changed, 472 insertions(+)
>   create mode 100644 Documentation/technical/protocol-v2.txt
>   create mode 100644 builtin/serve.c
>   create mode 100644 serve.c
>   create mode 100644 serve.h
>   create mode 100755 t/t5701-git-serve.sh
>
> diff --git a/.gitignore b/.gitignore
> index 833ef3b0b..2d0450c26 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -140,6 +140,7 @@
>   /git-rm
>   /git-send-email
>   /git-send-pack
> +/git-serve
>   /git-sh-i18n
>   /git-sh-i18n--envsubst
>   /git-sh-setup
> diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
> new file mode 100644
> index 000000000..7f619a76c
> --- /dev/null
> +++ b/Documentation/technical/protocol-v2.txt
> @@ -0,0 +1,117 @@
> + Git Wire Protocol, Version 2
> +==============================
> +
> +This document presents a specification for a version 2 of Git's wire
> +protocol.  Protocol v2 will improve upon v1 in the following ways:
> +
> +  * Instead of multiple service names, multiple commands will be
> +    supported by a single service.

As someone unfamiliar with the old protocol code, this statement is 
underselling the architectural significance of your change. The new 
model allows a single service to handle all different wire protocols 
(git://, ssh://, https://) while being agnostic to the command-specific 
logic. It also hides the protocol negotiation away from these consumers.

The ease with which you are adding new commands in later commits really 
demonstrates the value of this patch. To make that point here, you would 
almost need to document the old model to show how it was difficult to 
use and extend. Perhaps this document will not need expanding since the 
code speaks for itself.

I just wanted to state for the record that the new architecture is a big 
improvement and will make more commands much easier to implement.

> +  * Easily extendable as capabilities are moved into their own section
> +    of the protocol, no longer being hidden behind a NUL byte and
> +    limited by the size of a pkt-line (as there will be a single
> +    capability per pkt-line).
> +  * Separate out other information hidden behind NUL bytes (e.g. agent
> +    string as a capability and symrefs can be requested using 'ls-refs')
> +  * Reference advertisement will be omitted unless explicitly requested
> +  * ls-refs command to explicitly request some refs
> +

nit: some bullets have full stops (.) and others do not.

> + Detailed Design
> +=================
> +
> +A client can request to speak protocol v2 by sending `version=2` in the
> +side-channel `GIT_PROTOCOL` in the initial request to the server.
> +
> +In protocol v2 communication is command oriented.  When first contacting a
> +server a list of capabilities will advertised.  Some of these capabilities
> +will be commands which a client can request be executed.  Once a command
> +has completed, a client can reuse the connection and request that other
> +commands be executed.
> +
> + Special Packets
> +-----------------
> +
> +In protocol v2 these special packets will have the following semantics:
> +
> +  * '0000' Flush Packet (flush-pkt) - indicates the end of a message
> +  * '0001' Delimiter Packet (delim-pkt) - separates sections of a message
> +
> + Capability Advertisement
> +--------------------------
> +
> +A server which decides to communicate (based on a request from a client)
> +using protocol version 2, notifies the client by sending a version string
> +in its initial response followed by an advertisement of its capabilities.
> +Each capability is a key with an optional value.  Clients must ignore all
> +unknown keys.  Semantics of unknown values are left to the definition of
> +each key.  Some capabilities will describe commands which can be requested
> +to be executed by the client.
> +
> +    capability-advertisement = protocol-version
> +			       capability-list
> +			       flush-pkt
> +
> +    protocol-version = PKT-LINE("version 2" LF)
> +    capability-list = *capability
> +    capability = PKT-LINE(key[=value] LF)
> +
> +    key = 1*CHAR
> +    value = 1*CHAR
> +    CHAR = 1*(ALPHA / DIGIT / "-" / "_")
> +
> +A client then responds to select the command it wants with any particular
> +capabilities or arguments.  There is then an optional section where the
> +client can provide any command specific parameters or queries.
> +
> +    command-request = command
> +		      capability-list
> +		      (command-args)
> +		      flush-pkt
> +    command = PKT-LINE("command=" key LF)
> +    command-args = delim-pkt
> +		   *arg
> +    arg = 1*CHAR
> +
> +The server will then check to ensure that the client's request is
> +comprised of a valid command as well as valid capabilities which were
> +advertised.  If the request is valid the server will then execute the
> +command.
> +
> +When a command has finished a client can either request that another
> +command be executed or can terminate the connection by sending an empty
> +request consisting of just a flush-pkt.
> +
> + Capabilities
> +~~~~~~~~~~~~~~
> +
> +There are two different types of capabilities: normal capabilities,
> +which can be used to to convey information or alter the behavior of a
> +request, and command capabilities, which are the core actions that a
> +client wants to perform (fetch, push, etc).
> +
> + agent
> +-------
> +
> +The server can advertise the `agent` capability with a value `X` (in the
> +form `agent=X`) to notify the client that the server is running version
> +`X`.  The client may optionally send its own agent string by including
> +the `agent` capability with a value `Y` (in the form `agent=Y`) in its
> +request to the server (but it MUST NOT do so if the server did not
> +advertise the agent capability). The `X` and `Y` strings may contain any
> +printable ASCII characters except space (i.e., the byte range 32 < x <
> +127), and are typically of the form "package/version" (e.g.,
> +"git/1.8.3.1"). The agent strings are purely informative for statistics
> +and debugging purposes, and MUST NOT be used to programmatically assume
> +the presence or absence of particular features.
> +
> + stateless-rpc
> +---------------
> +
> +If advertised, the `stateless-rpc` capability indicates that the server
> +supports running commands in a stateless-rpc mode, which means that a
> +command lasts for only a single request-response round.
> +
> +Normally a command can last for as many rounds as are required to
> +complete it (multiple for negotiation during fetch or no additional
> +trips in the case of ls-refs).  If the client sends the `stateless-rpc`
> +capability with a value of `true` (in the form `stateless-rpc=true`)
> +then the invoked command must only last a single round.
> diff --git a/Makefile b/Makefile
> index 3b849c060..18c255428 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -881,6 +881,7 @@ LIB_OBJS += revision.o
>   LIB_OBJS += run-command.o
>   LIB_OBJS += send-pack.o
>   LIB_OBJS += sequencer.o
> +LIB_OBJS += serve.o
>   LIB_OBJS += server-info.o
>   LIB_OBJS += setup.o
>   LIB_OBJS += sha1-array.o
> @@ -1014,6 +1015,7 @@ BUILTIN_OBJS += builtin/rev-parse.o
>   BUILTIN_OBJS += builtin/revert.o
>   BUILTIN_OBJS += builtin/rm.o
>   BUILTIN_OBJS += builtin/send-pack.o
> +BUILTIN_OBJS += builtin/serve.o
>   BUILTIN_OBJS += builtin/shortlog.o
>   BUILTIN_OBJS += builtin/show-branch.o
>   BUILTIN_OBJS += builtin/show-ref.o
> diff --git a/builtin.h b/builtin.h
> index f332a1257..3f3fdfc28 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -215,6 +215,7 @@ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
>   extern int cmd_revert(int argc, const char **argv, const char *prefix);
>   extern int cmd_rm(int argc, const char **argv, const char *prefix);
>   extern int cmd_send_pack(int argc, const char **argv, const char *prefix);
> +extern int cmd_serve(int argc, const char **argv, const char *prefix);
>   extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
>   extern int cmd_show(int argc, const char **argv, const char *prefix);
>   extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
> diff --git a/builtin/serve.c b/builtin/serve.c
> new file mode 100644
> index 000000000..d3fd240bb
> --- /dev/null
> +++ b/builtin/serve.c
> @@ -0,0 +1,30 @@
> +#include "cache.h"
> +#include "builtin.h"
> +#include "parse-options.h"
> +#include "serve.h"
> +
> +static char const * const serve_usage[] = {
> +	N_("git serve [<options>]"),
> +	NULL
> +};
> +
> +int cmd_serve(int argc, const char **argv, const char *prefix)
> +{
> +	struct serve_options opts = SERVE_OPTIONS_INIT;
> +
> +	struct option options[] = {
> +		OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc,
> +			 N_("quit after a single request/response exchange")),
> +		OPT_BOOL(0, "advertise-capabilities", &opts.advertise_capabilities,
> +			 N_("exit immediately after advertising capabilities")),
> +		OPT_END()
> +	};
> +
> +	/* ignore all unknown cmdline switches for now */
> +	argc = parse_options(argc, argv, prefix, options, serve_usage,
> +			     PARSE_OPT_KEEP_DASHDASH |
> +			     PARSE_OPT_KEEP_UNKNOWN);
> +	serve(&opts);
> +
> +	return 0;
> +}
> diff --git a/git.c b/git.c
> index f71073dc8..f85d682b6 100644
> --- a/git.c
> +++ b/git.c
> @@ -461,6 +461,7 @@ static struct cmd_struct commands[] = {
>   	{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
>   	{ "rm", cmd_rm, RUN_SETUP },
>   	{ "send-pack", cmd_send_pack, RUN_SETUP },
> +	{ "serve", cmd_serve, RUN_SETUP },
>   	{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
>   	{ "show", cmd_show, RUN_SETUP },
>   	{ "show-branch", cmd_show_branch, RUN_SETUP },
> diff --git a/serve.c b/serve.c
> new file mode 100644
> index 000000000..90e3defe8
> --- /dev/null
> +++ b/serve.c
> @@ -0,0 +1,249 @@
> +#include "cache.h"
> +#include "repository.h"
> +#include "config.h"
> +#include "pkt-line.h"
> +#include "version.h"
> +#include "argv-array.h"
> +#include "serve.h"
> +
> +static int always_advertise(struct repository *r,
> +			    struct strbuf *value)
> +{
> +	return 1;
> +}
> +
> +static int agent_advertise(struct repository *r,
> +			   struct strbuf *value)
> +{
> +	if (value)
> +		strbuf_addstr(value, git_user_agent_sanitized());
> +	return 1;
> +}
> +
> +struct protocol_capability {
> +	/*
> +	 * The name of the capability.  The server uses this name when
> +	 * advertising this capability, and the client uses this name to
> +	 * specify this capability.
> +	 */
> +	const char *name;
> +
> +	/*
> +	 * Function queried to see if a capability should be advertised.
> +	 * Optionally a value can be specified by adding it to 'value'.
> +	 * If a value is added to 'value', the server will advertise this
> +	 * capability as "<name>=<value>" instead of "<name>".
> +	 */
> +	int (*advertise)(struct repository *r, struct strbuf *value);
> +
> +	/*
> +	 * Function called when a client requests the capability as a command.
> +	 * The command request will be provided to the function via 'keys', the
> +	 * capabilities requested, and 'args', the command specific parameters.
> +	 *
> +	 * This field should be NULL for capabilities which are not commands.
> +	 */
> +	int (*command)(struct repository *r,
> +		       struct argv_array *keys,
> +		       struct argv_array *args);
> +};
> +
> +static struct protocol_capability capabilities[] = {
> +	{ "agent", agent_advertise, NULL },
> +	{ "stateless-rpc", always_advertise, NULL },
> +};
> +
> +static void advertise_capabilities(void)
> +{
> +	struct strbuf capability = STRBUF_INIT;
> +	struct strbuf value = STRBUF_INIT;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
> +		struct protocol_capability *c = &capabilities[i];
> +
> +		if (c->advertise(the_repository, &value)) {
> +			strbuf_addstr(&capability, c->name);
> +
> +			if (value.len) {
> +				strbuf_addch(&capability, '=');
> +				strbuf_addbuf(&capability, &value);
> +			}
> +
> +			strbuf_addch(&capability, '\n');
> +			packet_write(1, capability.buf, capability.len);
> +		}
> +
> +		strbuf_reset(&capability);
> +		strbuf_reset(&value);
> +	}
> +
> +	packet_flush(1);
> +	strbuf_release(&capability);
> +	strbuf_release(&value);
> +}
> +
> +static struct protocol_capability *get_capability(const char *key)
> +{
> +	int i;
> +
> +	if (!key)
> +		return NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
> +		struct protocol_capability *c = &capabilities[i];
> +		const char *out;
> +		if (skip_prefix(key, c->name, &out) && (!*out || *out == '='))
> +			return c;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int is_valid_capability(const char *key)
> +{
> +	const struct protocol_capability *c = get_capability(key);
> +
> +	return c && c->advertise(the_repository, NULL);
> +}
> +
> +static int is_command(const char *key, struct protocol_capability **command)
> +{
> +	const char *out;
> +
> +	if (skip_prefix(key, "command=", &out)) {
> +		struct protocol_capability *cmd = get_capability(out);
> +
> +		if (!cmd || !cmd->advertise(the_repository, NULL) || !cmd->command)
> +			die("invalid command '%s'", out);
> +		if (*command)
> +			die("command already requested");
> +
> +		*command = cmd;
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int has_capability(const struct argv_array *keys, const char *capability,
> +		   const char **value)
> +{
> +	int i;
> +	for (i = 0; i < keys->argc; i++) {
> +		const char *out;
> +		if (skip_prefix(keys->argv[i], capability, &out) &&
> +		    (!*out || *out == '=')) {
> +			if (value) {
> +				if (*out == '=')
> +					out++;
> +				*value = out;
> +			}
> +			return 1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +enum request_state {
> +	PROCESS_REQUEST_KEYS = 0,
> +	PROCESS_REQUEST_ARGS,
> +	PROCESS_REQUEST_DONE,
> +};
> +
> +static int process_request(void)
> +{
> +	enum request_state state = PROCESS_REQUEST_KEYS;
> +	char *buffer = packet_buffer;
> +	unsigned buffer_size = sizeof(packet_buffer);
> +	int pktlen;
> +	struct argv_array keys = ARGV_ARRAY_INIT;
> +	struct argv_array args = ARGV_ARRAY_INIT;
> +	struct protocol_capability *command = NULL;
> +
> +	while (state != PROCESS_REQUEST_DONE) {
> +		switch (packet_read_with_status(0, NULL, NULL, buffer,
> +						buffer_size, &pktlen,
> +						PACKET_READ_CHOMP_NEWLINE)) {
> +		case PACKET_READ_EOF:
> +			BUG("Should have already died when seeing EOF");
> +		case PACKET_READ_NORMAL:
> +			break;
> +		case PACKET_READ_FLUSH:
> +			state = PROCESS_REQUEST_DONE;
> +			continue;
> +		case PACKET_READ_DELIM:
> +			if (state != PROCESS_REQUEST_KEYS)
> +				die("protocol error");
> +			state = PROCESS_REQUEST_ARGS;
> +			/*
> +			 * maybe include a check to make sure that a
> +			 * command/capabilities were given.
> +			 */
> +			continue;
> +		}
> +
> +		switch (state) {
> +		case PROCESS_REQUEST_KEYS:
> +			/* collect request; a sequence of keys and values */
> +			if (is_command(buffer, &command) ||
> +			    is_valid_capability(buffer))
> +				argv_array_push(&keys, buffer);
> +			else
> +				die("unknown capability '%s'", buffer);
> +			break;
> +		case PROCESS_REQUEST_ARGS:
> +			/* collect arguments for the requested command */
> +			argv_array_push(&args, buffer);
> +			break;
> +		case PROCESS_REQUEST_DONE:
> +			continue;
> +		}
> +	}
> +
> +	/*
> +	 * If no command and no keys were given then the client wanted to
> +	 * terminate the connection.
> +	 */
> +	if (!keys.argc && !args.argc)
> +		return 1;
> +
> +	if (!command)
> +		die("no command requested");
> +
> +	command->command(the_repository, &keys, &args);
> +
> +	argv_array_clear(&keys);
> +	argv_array_clear(&args);
> +	return 0;
> +}
> +
> +/* Main serve loop for protocol version 2 */
> +void serve(struct serve_options *options)
> +{
> +	if (options->advertise_capabilities || !options->stateless_rpc) {
> +		/* serve by default supports v2 */
> +		packet_write_fmt(1, "version 2\n");
> +
> +		advertise_capabilities();
> +		/*
> +		 * If only the list of capabilities was requested exit
> +		 * immediately after advertising capabilities
> +		 */
> +		if (options->advertise_capabilities)
> +			return;
> +	}
> +
> +	/*
> +	 * If stateless-rpc was requested then exit after
> +	 * a single request/response exchange
> +	 */
> +	if (options->stateless_rpc) {
> +		process_request();
> +	} else {
> +		for (;;)
> +			if (process_request())
> +				break;
> +	}
> +}
> diff --git a/serve.h b/serve.h
> new file mode 100644
> index 000000000..fe65ba9f4
> --- /dev/null
> +++ b/serve.h
> @@ -0,0 +1,15 @@
> +#ifndef SERVE_H
> +#define SERVE_H
> +
> +struct argv_array;
> +extern int has_capability(const struct argv_array *keys, const char *capability,
> +			  const char **value);
> +
> +struct serve_options {
> +	unsigned advertise_capabilities;
> +	unsigned stateless_rpc;
> +};
> +#define SERVE_OPTIONS_INIT { 0 }
> +extern void serve(struct serve_options *options);
> +
> +#endif /* SERVE_H */
> diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
> new file mode 100755
> index 000000000..b5cc049e5
> --- /dev/null
> +++ b/t/t5701-git-serve.sh
> @@ -0,0 +1,56 @@
> +#!/bin/sh
> +
> +test_description='test git-serve and server commands'
> +
> +. ./test-lib.sh
> +
> +test_expect_success 'test capability advertisement' '
> +	cat >expect <<-EOF &&
> +	version 2
> +	agent=git/$(git version | cut -d" " -f3)
> +	stateless-rpc
> +	0000
> +	EOF
> +
> +	git serve --advertise-capabilities >out &&
> +	test-pkt-line unpack <out >actual &&
> +	test_cmp actual expect
> +'
> +
> +test_expect_success 'stateless-rpc flag does not list capabilities' '
> +	test-pkt-line pack >in <<-EOF &&
> +	0000
> +	EOF
> +	git serve --stateless-rpc >out <in &&
> +	test_must_be_empty out
> +'
> +
> +test_expect_success 'request invalid capability' '
> +	test-pkt-line pack >in <<-EOF &&
> +	foobar
> +	0000
> +	EOF
> +	test_must_fail git serve --stateless-rpc 2>err <in &&
> +	test_i18ngrep "unknown capability" err
> +'
> +
> +test_expect_success 'request with no command' '
> +	test-pkt-line pack >in <<-EOF &&
> +	agent=git/test
> +	0000
> +	EOF
> +	test_must_fail git serve --stateless-rpc 2>err <in &&
> +	test_i18ngrep "no command requested" err
> +'
> +
> +test_expect_success 'request invalid command' '
> +	test-pkt-line pack >in <<-EOF &&
> +	command=foo
> +	agent=git/test
> +	0000
> +	EOF
> +	test_must_fail git serve --stateless-rpc 2>err <in &&
> +	test_i18ngrep "invalid command" err
> +'
> +
> +test_done


  parent reply index

Thread overview: 361+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-03  0:18 [PATCH 00/26] protocol version 2 Brandon Williams
2018-01-03  0:18 ` [PATCH 01/26] pkt-line: introduce packet_read_with_status Brandon Williams
2018-01-03 19:27   ` Stefan Beller
2018-01-05 23:41     ` Brandon Williams
2018-01-09 18:04   ` Jonathan Tan
2018-01-09 19:28     ` Brandon Williams
2018-01-03  0:18 ` [PATCH 02/26] pkt-line: introduce struct packet_reader Brandon Williams
2018-01-09 18:08   ` Jonathan Tan
2018-01-09 19:19     ` Brandon Williams
2018-01-03  0:18 ` [PATCH 03/26] pkt-line: add delim packet support Brandon Williams
2018-01-03  0:18 ` [PATCH 04/26] upload-pack: convert to a builtin Brandon Williams
2018-01-03 20:33   ` Stefan Beller
2018-01-03 20:39     ` Brandon Williams
2018-02-21 21:47       ` Jonathan Nieder
2018-02-21 23:35         ` Junio C Hamano
2018-01-03  0:18 ` [PATCH 05/26] upload-pack: factor out processing lines Brandon Williams
2018-01-03 20:38   ` Stefan Beller
2018-01-03  0:18 ` [PATCH 06/26] transport: use get_refs_via_connect to get refs Brandon Williams
2018-01-03 21:20   ` Stefan Beller
2018-01-03  0:18 ` [PATCH 07/26] connect: convert get_remote_heads to use struct packet_reader Brandon Williams
2018-01-09 18:27   ` Jonathan Tan
2018-01-09 19:09     ` Brandon Williams
2018-01-03  0:18 ` [PATCH 08/26] connect: discover protocol version outside of get_remote_heads Brandon Williams
2018-01-03  0:18 ` [PATCH 09/26] transport: store protocol version Brandon Williams
2018-01-09 18:41   ` Jonathan Tan
2018-01-09 19:15     ` Brandon Williams
2018-01-03  0:18 ` [PATCH 10/26] protocol: introduce enum protocol_version value protocol_v2 Brandon Williams
2018-01-03  0:18 ` [PATCH 11/26] serve: introduce git-serve Brandon Williams
2018-01-09 20:24   ` Jonathan Tan
2018-01-09 22:16     ` Brandon Williams
2018-01-09 22:28       ` Jonathan Tan
2018-01-09 22:34         ` Brandon Williams
2018-02-01 18:48   ` Jeff Hostetler
2018-02-01 18:57     ` Stefan Beller
2018-02-01 19:09       ` Jeff Hostetler
2018-02-01 20:05         ` Brandon Williams
2018-02-01 19:45       ` Randall S. Becker
2018-02-01 20:08         ` Brandon Williams
2018-02-01 20:37           ` Randall S. Becker
2018-02-01 20:50             ` Stefan Beller
2018-01-03  0:18 ` [PATCH 12/26] ls-refs: introduce ls-refs server command Brandon Williams
2018-01-04  0:17   ` Stefan Beller
2018-01-05 23:49     ` Brandon Williams
2018-01-09 20:50   ` Jonathan Tan
2018-01-16 19:23     ` Brandon Williams
2018-02-01 19:16   ` Jeff Hostetler
2018-02-07  0:55     ` Brandon Williams
2018-01-03  0:18 ` [PATCH 13/26] connect: request remote refs using v2 Brandon Williams
2018-01-09 22:24   ` Jonathan Tan
2018-01-03  0:18 ` [PATCH 14/26] transport: convert get_refs_list to take a list of ref patterns Brandon Williams
2018-01-03  0:18 ` [PATCH 15/26] transport: convert transport_get_remote_refs " Brandon Williams
2018-01-03  0:18 ` [PATCH 16/26] ls-remote: pass ref patterns when requesting a remote's refs Brandon Williams
2018-01-03  0:18 ` [PATCH 17/26] fetch: pass ref patterns when fetching Brandon Williams
2018-01-03  0:18 ` [PATCH 18/26] push: pass ref patterns when pushing Brandon Williams
2018-01-03  0:18 ` [PATCH 19/26] upload-pack: introduce fetch server command Brandon Williams
2018-01-04  1:07   ` Stefan Beller
2018-01-03  0:18 ` [PATCH 20/26] fetch-pack: perform a fetch using v2 Brandon Williams
2018-01-04  1:23   ` Stefan Beller
2018-01-05 23:55     ` Brandon Williams
2018-01-10  0:05   ` Jonathan Tan
2018-01-03  0:18 ` [PATCH 21/26] transport-helper: remove name parameter Brandon Williams
2018-01-03  0:18 ` [PATCH 22/26] transport-helper: refactor process_connect_service Brandon Williams
2018-01-03  0:18 ` [PATCH 23/26] transport-helper: introduce connect-half-duplex Brandon Williams
2018-01-03  0:18 ` [PATCH 24/26] pkt-line: add packet_buf_write_len function Brandon Williams
2018-01-03  0:18 ` [PATCH 25/26] remote-curl: create copy of the service name Brandon Williams
2018-01-03  0:18 ` [PATCH 26/26] remote-curl: implement connect-half-duplex command Brandon Williams
2018-01-10  0:10   ` Jonathan Tan
2018-01-10 17:57   ` Jonathan Tan
2018-01-11  1:09     ` Brandon Williams
2018-01-09 17:55 ` [PATCH 00/26] protocol version 2 Jonathan Tan
2018-01-11  0:23   ` Brandon Williams
2018-01-25 23:58 ` [PATCH v2 00/27] " Brandon Williams
2018-01-25 23:58   ` [PATCH v2 01/27] pkt-line: introduce packet_read_with_status Brandon Williams
2018-01-25 23:58   ` [PATCH v2 02/27] pkt-line: introduce struct packet_reader Brandon Williams
2018-01-25 23:58   ` [PATCH v2 03/27] pkt-line: add delim packet support Brandon Williams
2018-01-25 23:58   ` [PATCH v2 04/27] upload-pack: convert to a builtin Brandon Williams
2018-01-25 23:58   ` [PATCH v2 05/27] upload-pack: factor out processing lines Brandon Williams
2018-01-26 20:12     ` Stefan Beller
2018-01-26 21:33       ` Brandon Williams
2018-01-31 14:08         ` Derrick Stolee
2018-01-25 23:58   ` [PATCH v2 06/27] transport: use get_refs_via_connect to get refs Brandon Williams
2018-01-25 23:58   ` [PATCH v2 07/27] connect: convert get_remote_heads to use struct packet_reader Brandon Williams
2018-01-25 23:58   ` [PATCH v2 08/27] connect: discover protocol version outside of get_remote_heads Brandon Williams
2018-01-31 14:40     ` Derrick Stolee
2018-02-01 17:57       ` Brandon Williams
2018-01-25 23:58   ` [PATCH v2 09/27] transport: store protocol version Brandon Williams
2018-01-31 14:45     ` Derrick Stolee
2018-01-25 23:58   ` [PATCH v2 10/27] protocol: introduce enum protocol_version value protocol_v2 Brandon Williams
2018-01-31 14:54     ` Derrick Stolee
2018-02-02 22:44       ` Brandon Williams
2018-02-05 14:14         ` Derrick Stolee
2018-01-25 23:58   ` [PATCH v2 11/27] test-pkt-line: introduce a packet-line test helper Brandon Williams
2018-01-25 23:58   ` [PATCH v2 12/27] serve: introduce git-serve Brandon Williams
2018-01-26 10:39     ` Duy Nguyen
2018-02-27  5:46       ` Jonathan Nieder
2018-01-31 15:39     ` Derrick Stolee [this message]
2018-01-25 23:58   ` [PATCH v2 13/27] ls-refs: introduce ls-refs server command Brandon Williams
2018-01-26 22:20     ` Stefan Beller
2018-02-02 22:31       ` Brandon Williams
2018-01-25 23:58   ` [PATCH v2 14/27] connect: request remote refs using v2 Brandon Williams
2018-01-31 15:22     ` Derrick Stolee
2018-01-31 20:10       ` Eric Sunshine
2018-01-31 22:14         ` Derrick Stolee
2018-01-25 23:58   ` [PATCH v2 15/27] transport: convert get_refs_list to take a list of ref patterns Brandon Williams
2018-01-25 23:58   ` [PATCH v2 16/27] transport: convert transport_get_remote_refs " Brandon Williams
2018-01-25 23:58   ` [PATCH v2 17/27] ls-remote: pass ref patterns when requesting a remote's refs Brandon Williams
2018-01-25 23:58   ` [PATCH v2 18/27] fetch: pass ref patterns when fetching Brandon Williams
2018-01-25 23:58   ` [PATCH v2 19/27] push: pass ref patterns when pushing Brandon Williams
2018-01-25 23:58   ` [PATCH v2 20/27] upload-pack: introduce fetch server command Brandon Williams
2018-01-25 23:58   ` [PATCH v2 21/27] fetch-pack: perform a fetch using v2 Brandon Williams
2018-01-25 23:58   ` [PATCH v2 22/27] transport-helper: remove name parameter Brandon Williams
2018-01-25 23:58   ` [PATCH v2 23/27] transport-helper: refactor process_connect_service Brandon Williams
2018-01-25 23:58   ` [PATCH v2 24/27] transport-helper: introduce stateless-connect Brandon Williams
2018-01-25 23:58   ` [PATCH v2 25/27] pkt-line: add packet_buf_write_len function Brandon Williams
2018-01-25 23:58   ` [PATCH v2 26/27] remote-curl: create copy of the service name Brandon Williams
2018-01-25 23:58   ` [PATCH v2 27/27] remote-curl: implement stateless-connect command Brandon Williams
2018-01-31 16:00   ` [PATCH v2 00/27] protocol version 2 Derrick Stolee
2018-02-07  0:58     ` Brandon Williams
2018-02-01 19:40   ` Jeff Hostetler
2018-02-07  1:12   ` [PATCH v3 00/35] " Brandon Williams
2018-02-07  1:12     ` [PATCH v3 01/35] pkt-line: introduce packet_read_with_status Brandon Williams
2018-02-13  0:25       ` Jonathan Nieder
2018-02-07  1:12     ` [PATCH v3 02/35] pkt-line: introduce struct packet_reader Brandon Williams
2018-02-13  0:49       ` Jonathan Nieder
2018-02-27 18:14         ` Brandon Williams
2018-02-27 19:20           ` Jonathan Nieder
2018-02-27  5:57       ` Jonathan Nieder
2018-02-27  6:12         ` Jonathan Nieder
2018-02-07  1:12     ` [PATCH v3 03/35] pkt-line: add delim packet support Brandon Williams
2018-02-22 19:13       ` Stefan Beller
2018-02-22 19:37         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 04/35] upload-pack: convert to a builtin Brandon Williams
2018-02-21 21:44       ` Jonathan Tan
2018-02-22  9:58         ` Jeff King
2018-02-22 18:07           ` Brandon Williams
2018-02-22 18:14             ` Jeff King
2018-02-22 19:38               ` Jonathan Nieder
2018-02-22 20:19                 ` Jeff King
2018-02-22 20:21                   ` Jeff King
2018-02-22 21:26                     ` Jonathan Nieder
2018-02-22 21:44                       ` Jeff King
2018-03-12 22:43                         ` Jonathan Nieder
2018-03-12 23:28                           ` Jeff King
2018-03-12 23:37                             ` Jonathan Nieder
2018-03-12 23:52                               ` Jeff King
2018-02-23 21:09                     ` Brandon Williams
2018-03-03  4:24                       ` Jeff King
2018-02-22 21:24                   ` Jonathan Nieder
2018-02-22 21:44                     ` Jeff King
2018-02-22 22:21                       ` Jeff King
2018-02-22 22:42                         ` Jonathan Nieder
2018-02-22 23:05                           ` Jeff King
2018-02-22 23:23                             ` Jeff King
2018-02-07  1:12     ` [PATCH v3 05/35] upload-pack: factor out processing lines Brandon Williams
2018-02-22 19:31       ` Stefan Beller
2018-02-22 19:39         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 06/35] transport: use get_refs_via_connect to get refs Brandon Williams
2018-02-27  6:08       ` Jonathan Nieder
2018-02-27 18:17         ` Brandon Williams
2018-02-27 19:25           ` Jonathan Nieder
2018-02-27 19:46             ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 07/35] connect: convert get_remote_heads to use struct packet_reader Brandon Williams
2018-02-22 19:52       ` Stefan Beller
2018-02-22 20:09       ` Stefan Beller
2018-02-23 21:30         ` Brandon Williams
2018-02-23 21:48           ` Stefan Beller
2018-02-23 22:56             ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 08/35] connect: discover protocol version outside of get_remote_heads Brandon Williams
2018-02-21 22:11       ` Jonathan Tan
2018-02-22 18:17         ` Brandon Williams
2018-02-22 19:22           ` Jonathan Tan
2018-02-07  1:12     ` [PATCH v3 09/35] transport: store protocol version Brandon Williams
2018-02-07  1:12     ` [PATCH v3 10/35] protocol: introduce enum protocol_version value protocol_v2 Brandon Williams
2018-02-27  6:18       ` Jonathan Nieder
2018-02-27 18:41         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 11/35] test-pkt-line: introduce a packet-line test helper Brandon Williams
2018-02-22 20:40       ` Stefan Beller
2018-02-23 21:22         ` Brandon Williams
2018-03-03  4:25           ` Jeff King
2018-03-05 18:48             ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 12/35] serve: introduce git-serve Brandon Williams
2018-02-21 22:45       ` Jonathan Tan
2018-02-23 21:33         ` Brandon Williams
2018-02-27 18:05           ` Jonathan Tan
2018-02-27 18:34             ` Brandon Williams
2018-02-22  9:33       ` Jeff King
2018-02-23 21:45         ` Brandon Williams
2018-03-03  4:33           ` Jeff King
2018-03-05 18:43             ` Brandon Williams
2018-03-05 20:52               ` Jeff King
2018-03-05 21:36                 ` Jonathan Nieder
2018-03-06  6:29                   ` Jeff King
2018-03-12 23:46                     ` Jeff King
2018-02-07  1:12     ` [PATCH v3 13/35] ls-refs: introduce ls-refs server command Brandon Williams
2018-02-22  9:48       ` Jeff King
2018-02-23  0:45         ` Brandon Williams
2018-02-24  0:19           ` Brandon Williams
2018-02-24  4:03             ` Jeff King
2018-02-24  4:01           ` Jeff King
2018-02-26 22:33             ` Junio C Hamano
2018-02-27  0:02             ` Ævar Arnfjörð Bjarmason
2018-02-27  5:15               ` Jonathan Nieder
2018-02-27 18:02                 ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 14/35] connect: request remote refs using v2 Brandon Williams
2018-02-21 22:54       ` Jonathan Tan
2018-02-22 18:19         ` Brandon Williams
2018-02-22 18:26           ` Jeff King
2018-02-22 19:25             ` Jonathan Tan
2018-02-27  6:21               ` Jonathan Nieder
2018-02-27 21:58                 ` Junio C Hamano
2018-02-27 22:04                   ` Jeff King
2018-02-27 22:10                     ` Eric Sunshine
2018-02-27 22:18                       ` Jeff King
2018-02-27 23:32                         ` Junio C Hamano
2018-02-27  6:51       ` Jonathan Nieder
2018-02-27 19:30         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 15/35] transport: convert get_refs_list to take a list of ref patterns Brandon Williams
2018-02-21 22:56       ` Jonathan Tan
2018-02-22 18:25         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 16/35] transport: convert transport_get_remote_refs " Brandon Williams
2018-02-21 22:58       ` Jonathan Tan
2018-02-22 18:26         ` Brandon Williams
2018-02-22 19:32           ` Jonathan Tan
2018-02-22 19:51             ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 17/35] ls-remote: pass ref patterns when requesting a remote's refs Brandon Williams
2018-02-07  1:12     ` [PATCH v3 18/35] fetch: pass ref patterns when fetching Brandon Williams
2018-02-27  6:53       ` Jonathan Nieder
2018-02-07  1:12     ` [PATCH v3 19/35] push: pass ref patterns when pushing Brandon Williams
2018-02-27 18:23       ` Stefan Beller
2018-02-07  1:12     ` [PATCH v3 20/35] upload-pack: introduce fetch server command Brandon Williams
2018-02-21 23:46       ` Jonathan Tan
2018-02-22 18:48         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 21/35] fetch-pack: perform a fetch using v2 Brandon Williams
2018-02-24  0:54       ` Jonathan Tan
2018-02-26 22:23         ` Brandon Williams
2018-02-27 19:27       ` Stefan Beller
2018-02-27 19:40         ` Brandon Williams
2018-02-07  1:12     ` [PATCH v3 22/35] upload-pack: support shallow requests Brandon Williams
2018-02-07 19:00       ` Stefan Beller
2018-02-10 10:23         ` Duy Nguyen
2018-02-13 17:06         ` Brandon Williams
2018-02-27 18:29       ` Jonathan Nieder
2018-02-27 18:57         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 23/35] fetch-pack: " Brandon Williams
2018-02-23 19:37       ` Jonathan Tan
2018-02-23 19:56         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 24/35] connect: refactor git_connect to only get the protocol version once Brandon Williams
2018-02-21 23:51       ` Jonathan Tan
2018-02-07  1:13     ` [PATCH v3 25/35] connect: don't request v2 when pushing Brandon Williams
2018-02-07  1:13     ` [PATCH v3 26/35] transport-helper: remove name parameter Brandon Williams
2018-02-27 23:03       ` Jonathan Nieder
2018-02-07  1:13     ` [PATCH v3 27/35] transport-helper: refactor process_connect_service Brandon Williams
2018-02-07  1:13     ` [PATCH v3 28/35] transport-helper: introduce stateless-connect Brandon Williams
2018-02-22  0:01       ` Jonathan Tan
2018-02-22 18:53         ` Brandon Williams
2018-02-22 21:55           ` Jonathan Tan
2018-02-27 23:30       ` Jonathan Nieder
2018-02-28 19:09         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 29/35] pkt-line: add packet_buf_write_len function Brandon Williams
2018-02-27 23:11       ` Jonathan Nieder
2018-02-28  1:08         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 30/35] remote-curl: create copy of the service name Brandon Williams
2018-02-22  0:06       ` Jonathan Tan
2018-02-22 18:56         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 31/35] remote-curl: store the protocol version the server responded with Brandon Williams
2018-02-27 23:17       ` Jonathan Nieder
2018-02-07  1:13     ` [PATCH v3 32/35] http: allow providing extra headers for http requests Brandon Williams
2018-02-22  0:09       ` Jonathan Tan
2018-02-22 18:58         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 33/35] http: don't always add Git-Protocol header Brandon Williams
2018-02-07  1:13     ` [PATCH v3 34/35] remote-curl: implement stateless-connect command Brandon Williams
2018-02-28  0:05       ` Jonathan Nieder
2018-02-28 20:21         ` Brandon Williams
2018-02-07  1:13     ` [PATCH v3 35/35] remote-curl: don't request v2 when pushing Brandon Williams
2018-02-22  0:12       ` Jonathan Tan
2018-02-22 18:59         ` Brandon Williams
2018-02-22 19:09           ` Brandon Williams
2018-02-12 14:50     ` [PATCH v3 00/35] protocol version 2 Derrick Stolee
2018-02-21 20:01     ` Brandon Williams
2018-02-28 23:22     ` [PATCH v4 " Brandon Williams
2018-02-28 23:22       ` [PATCH v4 01/35] pkt-line: introduce packet_read_with_status Brandon Williams
2018-03-13 19:35         ` Jonathan Tan
2018-03-13 19:52           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 02/35] pkt-line: allow peeking a packet line without consuming it Brandon Williams
2018-03-01 20:48         ` Junio C Hamano
2018-03-12 21:56           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 03/35] pkt-line: add delim packet support Brandon Williams
2018-03-01 20:50         ` Junio C Hamano
2018-03-01 21:04           ` Junio C Hamano
2018-03-01 22:49             ` Brandon Williams
2018-03-01 23:43               ` Junio C Hamano
2018-02-28 23:22       ` [PATCH v4 04/35] upload-pack: convert to a builtin Brandon Williams
2018-03-13 16:40         ` Jonathan Tan
2018-03-13 19:50           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 05/35] upload-pack: factor out processing lines Brandon Williams
2018-03-01 21:25         ` Junio C Hamano
2018-03-12 22:24           ` Brandon Williams
2018-03-12 22:39             ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 06/35] transport: use get_refs_via_connect to get refs Brandon Williams
2018-03-01 21:25         ` Junio C Hamano
2018-02-28 23:22       ` [PATCH v4 07/35] connect: convert get_remote_heads to use struct packet_reader Brandon Williams
2018-02-28 23:22       ` [PATCH v4 08/35] connect: discover protocol version outside of get_remote_heads Brandon Williams
2018-03-13 15:49         ` Jonathan Tan
2018-02-28 23:22       ` [PATCH v4 09/35] transport: store protocol version Brandon Williams
2018-02-28 23:22       ` [PATCH v4 10/35] protocol: introduce enum protocol_version value protocol_v2 Brandon Williams
2018-02-28 23:22       ` [PATCH v4 11/35] test-pkt-line: introduce a packet-line test helper Brandon Williams
2018-02-28 23:22       ` [PATCH v4 12/35] serve: introduce git-serve Brandon Williams
2018-03-01 23:11         ` Junio C Hamano
2018-03-12 22:08           ` Brandon Williams
2018-03-02 20:42         ` Junio C Hamano
2018-03-13 21:40           ` Brandon Williams
2018-03-02 20:56         ` Junio C Hamano
2018-03-13 21:35           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 13/35] ls-refs: introduce ls-refs server command Brandon Williams
2018-03-02 21:13         ` Junio C Hamano
2018-03-13 21:27           ` Brandon Williams
2018-03-03  4:43         ` Jeff King
2018-03-05 18:21           ` Brandon Williams
2018-03-05 18:29             ` Jonathan Nieder
2018-03-05 20:38               ` Jeff King
2018-03-05 20:28             ` Jeff King
2018-03-13 21:23               ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 14/35] connect: request remote refs using v2 Brandon Williams
2018-02-28 23:22       ` [PATCH v4 15/35] transport: convert get_refs_list to take a list of ref patterns Brandon Williams
2018-02-28 23:22       ` [PATCH v4 16/35] transport: convert transport_get_remote_refs " Brandon Williams
2018-03-13 16:00         ` Jonathan Tan
2018-02-28 23:22       ` [PATCH v4 17/35] ls-remote: pass ref patterns when requesting a remote's refs Brandon Williams
2018-03-02 22:13         ` Junio C Hamano
2018-02-28 23:22       ` [PATCH v4 18/35] fetch: pass ref patterns when fetching Brandon Williams
2018-03-02 22:20         ` Junio C Hamano
2018-03-12 22:18           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 19/35] push: pass ref patterns when pushing Brandon Williams
2018-03-02 22:25         ` Junio C Hamano
2018-03-12 22:20           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 20/35] upload-pack: introduce fetch server command Brandon Williams
2018-03-13 16:20         ` Jonathan Tan
2018-03-13 21:49           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 21/35] fetch-pack: perform a fetch using v2 Brandon Williams
2018-02-28 23:22       ` [PATCH v4 22/35] fetch-pack: support shallow requests Brandon Williams
2018-02-28 23:22       ` [PATCH v4 23/35] connect: refactor git_connect to only get the protocol version once Brandon Williams
2018-02-28 23:22       ` [PATCH v4 24/35] connect: don't request v2 when pushing Brandon Williams
2018-02-28 23:22       ` [PATCH v4 25/35] transport-helper: remove name parameter Brandon Williams
2018-02-28 23:22       ` [PATCH v4 26/35] transport-helper: refactor process_connect_service Brandon Williams
2018-02-28 23:22       ` [PATCH v4 27/35] transport-helper: introduce stateless-connect Brandon Williams
2018-03-13 16:30         ` Jonathan Tan
2018-03-14 17:36           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 28/35] pkt-line: add packet_buf_write_len function Brandon Williams
2018-02-28 23:22       ` [PATCH v4 29/35] remote-curl: create copy of the service name Brandon Williams
2018-03-13 16:32         ` Jonathan Tan
2018-02-28 23:22       ` [PATCH v4 30/35] remote-curl: store the protocol version the server responded with Brandon Williams
2018-02-28 23:22       ` [PATCH v4 31/35] http: allow providing extra headers for http requests Brandon Williams
2018-03-13 16:33         ` Jonathan Tan
2018-02-28 23:22       ` [PATCH v4 32/35] http: don't always add Git-Protocol header Brandon Williams
2018-02-28 23:22       ` [PATCH v4 33/35] http: eliminate "# service" line when using protocol v2 Brandon Williams
2018-02-28 23:22       ` [PATCH v4 34/35] remote-curl: implement stateless-connect command Brandon Williams
2018-03-02 20:07         ` Johannes Schindelin
2018-03-05 19:35           ` Brandon Williams
2018-02-28 23:22       ` [PATCH v4 35/35] remote-curl: don't request v2 when pushing Brandon Williams
2018-03-13 16:35         ` Jonathan Tan
2018-03-01 18:41       ` [PATCH v4 00/35] protocol version 2 Junio C Hamano
2018-03-01 19:16         ` Brandon Williams
2018-03-01 20:59           ` Junio C Hamano

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a9500d32-3f0a-4979-dcde-fb2acf0b3434@gmail.com \
    --to=stolee@gmail.com \
    --cc=bmwill@google.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jrnieder@gmail.com \
    --cc=peff@peff.net \
    --cc=philipoakley@iee.org \
    --cc=sbeller@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

git@vger.kernel.org mailing list mirror (one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox