Teach ls-remote to optionally accept server options by specifying them on the cmdline via '-o' or '--server-option'. These server options are sent to the remote end when querying for the remote end's refs using protocol version 2. If communicating using a protocol other than v2 the provided options are ignored and not sent to the remote end. Signed-off-by: Brandon Williams <bmwill@xxxxxxxxxx> --- Documentation/git-ls-remote.txt | 8 ++++++++ builtin/ls-remote.c | 4 ++++ connect.c | 9 ++++++++- remote.h | 4 +++- t/t5702-protocol-v2.sh | 16 ++++++++++++++++ transport.c | 2 +- transport.h | 6 ++++++ 7 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index 5f2628c8f..e5defb1b2 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -60,6 +60,14 @@ OPTIONS upload-pack only shows the symref HEAD, so it will be the only one shown by ls-remote. +-o <option>:: +--server-option=<option>:: + Transmit the given string to the server when communicating using + protocol version 2. The given string must not contain a NUL or LF + character. + When multiple `--server-option=<option>` are given, they are all + sent to the other side in the order listed on the command line. + <repository>:: The "remote" repository to query. This parameter can be either a URL or the name of a remote (see the GIT URLS and diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 380c18027..3150bfb92 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -45,6 +45,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) const char *uploadpack = NULL; const char **pattern = NULL; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; + struct string_list server_options = STRING_LIST_INIT_DUP; struct remote *remote; struct transport *transport; @@ -67,6 +68,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) 2, PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "symref", &show_symref_target, N_("show underlying ref in addition to the object pointed by it")), + OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")), OPT_END() }; @@ -107,6 +109,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) transport = transport_get(remote, NULL); if (uploadpack != NULL) transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); + if (server_options.nr) + transport->server_options = &server_options; ref = transport_get_remote_refs(transport, &ref_prefixes); if (transport_disconnect(transport)) diff --git a/connect.c b/connect.c index 54971166a..3000768c7 100644 --- a/connect.c +++ b/connect.c @@ -408,7 +408,8 @@ static int process_ref_v2(const char *line, struct ref ***list) struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, struct ref **list, int for_push, - const struct argv_array *ref_prefixes) + const struct argv_array *ref_prefixes, + const struct string_list *server_options) { int i; *list = NULL; @@ -419,6 +420,12 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, if (server_supports_v2("agent", 0)) packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized()); + if (server_options && server_options->nr && + server_supports_v2("server-option", 1)) + for (i = 0; i < server_options->nr; i++) + packet_write_fmt(fd_out, "server-option=%s", + server_options->items[i].string); + packet_delim(fd_out); /* When pushing we don't want to request the peeled tags */ if (!for_push) diff --git a/remote.h b/remote.h index 2b3180f94..93dd97e25 100644 --- a/remote.h +++ b/remote.h @@ -153,6 +153,7 @@ void free_refs(struct ref *ref); struct oid_array; struct packet_reader; struct argv_array; +struct string_list; extern struct ref **get_remote_heads(struct packet_reader *reader, struct ref **list, unsigned int flags, struct oid_array *extra_have, @@ -161,7 +162,8 @@ extern struct ref **get_remote_heads(struct packet_reader *reader, /* Used for protocol v2 in order to retrieve refs from a remote */ extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, struct ref **list, int for_push, - const struct argv_array *ref_prefixes); + const struct argv_array *ref_prefixes, + const struct string_list *server_options); int resolve_remote_symref(struct ref *ref, struct ref *list); int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 56f7c3c32..71ef1aee1 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -154,6 +154,22 @@ test_expect_success 'ref advertisment is filtered with ls-remote using protocol test_cmp actual expect ' +test_expect_success 'server-options are sent when using ls-remote' ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \ + ls-remote -o hello -o world "file://$(pwd)/file_parent" master >actual && + + cat >expect <<-EOF && + $(git -C file_parent rev-parse refs/heads/master)$(printf "\t")refs/heads/master + EOF + + test_cmp actual expect && + grep "server-option=hello" log && + grep "server-option=world" log +' + + test_expect_success 'clone with file:// using protocol v2' ' test_when_finished "rm -f log" && diff --git a/transport.c b/transport.c index 4d8beaaab..42fd468f3 100644 --- a/transport.c +++ b/transport.c @@ -218,7 +218,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus switch (data->version) { case protocol_v2: get_remote_refs(data->fd[1], &reader, &refs, for_push, - ref_prefixes); + ref_prefixes, transport->server_options); break; case protocol_v1: case protocol_v0: diff --git a/transport.h b/transport.h index e783cfa07..73a7be3c8 100644 --- a/transport.h +++ b/transport.h @@ -71,6 +71,12 @@ struct transport { */ const struct string_list *push_options; + /* + * These strings will be passed to the remote side on each command + * request, if both sides support the server-option capability. + */ + const struct string_list *server_options; + char *pack_lockfile; signed verbose : 3; /** -- 2.17.0.484.g0c8726318c-goog