transport.c:šŸ¤ make use of server options from remote

Utilize the `server_options` from the corresponding remote during the
handshake in `transport.c` when Git protocol v2 is detected. This helps
initialize the `server_options` in `transport.h:transport` if no server
options are set for the transport (typically via `--server-option` or
`-o`).

While another potential place to incorporate server options from the
remote is in `transport.c:transport_get`, setting server options for a
transport using a protocol other than v2 could lead to unexpected errors
(see `transport.c:die_if_server_options`).

Relevant tests and documentation have been updated accordingly.

Signed-off-by: Xing Xin <xingxin.xx@bytedance.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Xing Xin 2024-10-08 03:38:17 +00:00 committed by Junio C Hamano
parent 72da5cfb1c
commit 094f78a16a
5 changed files with 135 additions and 0 deletions

View File

@ -305,6 +305,9 @@ endif::git-pull[]
unknown ones, is server-specific. unknown ones, is server-specific.
When multiple `--server-option=<option>` are given, they are all When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line. sent to the other side in the order listed on the command line.
When no `--server-option=<option>` is given from the command line,
the values of configuration variable `remote.<name>.serverOption`
are used instead.


--show-forced-updates:: --show-forced-updates::
By default, git checks if a branch is force-updated during By default, git checks if a branch is force-updated during

View File

@ -149,6 +149,9 @@ objects from the source repository into a pack in the cloned repository.
unknown ones, is server-specific. unknown ones, is server-specific.
When multiple ++--server-option=++__<option>__ are given, they are all When multiple ++--server-option=++__<option>__ are given, they are all
sent to the other side in the order listed on the command line. sent to the other side in the order listed on the command line.
When no ++--server-option=++__<option>__ is given from the command
line, the values of configuration variable `remote.<name>.serverOption`
are used instead.


`-n`:: `-n`::
`--no-checkout`:: `--no-checkout`::

View File

@ -81,6 +81,9 @@ OPTIONS
character. character.
When multiple `--server-option=<option>` are given, they are all When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line. sent to the other side in the order listed on the command line.
When no `--server-option=<option>` is given from the command line,
the values of configuration variable `remote.<name>.serverOption`
are used instead.


<repository>:: <repository>::
The "remote" repository to query. This parameter can be The "remote" repository to query. This parameter can be

View File

@ -185,6 +185,43 @@ test_expect_success 'server-options are sent when using ls-remote' '
grep "server-option=world" log grep "server-option=world" log
' '


test_expect_success 'server-options from configuration are used by ls-remote' '
test_when_finished "rm -rf log myclone" &&
git clone "file://$(pwd)/file_parent" myclone &&
cat >expect <<-EOF &&
$(git -C file_parent rev-parse refs/heads/main)$(printf "\t")refs/heads/main
EOF

# Default server options from configuration are used
git -C myclone config --add remote.origin.serverOption foo &&
git -C myclone config --add remote.origin.serverOption bar &&
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
ls-remote origin main >actual &&
test_cmp expect actual &&
test_grep "ls-remote> server-option=foo" log &&
test_grep "ls-remote> server-option=bar" log &&
rm -f log &&

# Empty value of remote.<name>.serverOption clears the list
git -C myclone config --add remote.origin.serverOption "" &&
git -C myclone config --add remote.origin.serverOption tar &&
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
ls-remote origin main >actual &&
test_cmp expect actual &&
test_grep "ls-remote> server-option=tar" log &&
test_grep ! "ls-remote> server-option=foo" log &&
test_grep ! "ls-remote> server-option=bar" log &&
rm -f log &&

# Server option from command line overrides those from configuration
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
ls-remote -o hello -o world origin main >actual &&
test_cmp expect actual &&
test_grep "ls-remote> server-option=hello" log &&
test_grep "ls-remote> server-option=world" log &&
test_grep ! "ls-remote> server-option=tar" log
'

test_expect_success 'warn if using server-option with ls-remote with legacy protocol' ' test_expect_success 'warn if using server-option with ls-remote with legacy protocol' '
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \ test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err && ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err &&
@ -381,6 +418,44 @@ test_expect_success 'server-options are sent when fetching' '
grep "server-option=world" log grep "server-option=world" log
' '


test_expect_success 'server-options from configuration are used by git-fetch' '
test_when_finished "rm -rf log myclone" &&
git clone "file://$(pwd)/file_parent" myclone &&
git -C file_parent log -1 --format=%s >expect &&

# Default server options from configuration are used
git -C myclone config --add remote.origin.serverOption foo &&
git -C myclone config --add remote.origin.serverOption bar &&
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
fetch origin main &&
git -C myclone log -1 --format=%s origin/main >actual &&
test_cmp expect actual &&
test_grep "fetch> server-option=foo" log &&
test_grep "fetch> server-option=bar" log &&
rm -f log &&

# Empty value of remote.<name>.serverOption clears the list
git -C myclone config --add remote.origin.serverOption "" &&
git -C myclone config --add remote.origin.serverOption tar &&
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
fetch origin main &&
git -C myclone log -1 --format=%s origin/main >actual &&
test_cmp expect actual &&
test_grep "fetch> server-option=tar" log &&
test_grep ! "fetch> server-option=foo" log &&
test_grep ! "fetch> server-option=bar" log &&
rm -f log &&

# Server option from command line overrides those from configuration
GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
fetch -o hello -o world origin main &&
git -C myclone log -1 --format=%s origin/main >actual &&
test_cmp expect actual &&
test_grep "fetch> server-option=hello" log &&
test_grep "fetch> server-option=world" log &&
test_grep ! "fetch> server-option=tar" log
'

test_expect_success 'warn if using server-option with fetch with legacy protocol' ' test_expect_success 'warn if using server-option with fetch with legacy protocol' '
test_when_finished "rm -rf temp_child" && test_when_finished "rm -rf temp_child" &&


@ -404,6 +479,37 @@ test_expect_success 'server-options are sent when cloning' '
grep "server-option=world" log grep "server-option=world" log
' '


test_expect_success 'server-options from configuration are used by git-clone' '
test_when_finished "rm -rf log myclone" &&

# Default server options from configuration are used
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
-c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
clone "file://$(pwd)/file_parent" myclone &&
test_grep "clone> server-option=foo" log &&
test_grep "clone> server-option=bar" log &&
rm -rf log myclone &&

# Empty value of remote.<name>.serverOption clears the list
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
-c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
-c remote.origin.serverOption= -c remote.origin.serverOption=tar \
clone "file://$(pwd)/file_parent" myclone &&
test_grep "clone> server-option=tar" log &&
test_grep ! "clone> server-option=foo" log &&
test_grep ! "clone> server-option=bar" log &&
rm -rf log myclone &&

# Server option from command line overrides those from configuration
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
-c remote.origin.serverOption=tar \
clone --server-option=hello --server-option=world \
"file://$(pwd)/file_parent" myclone &&
test_grep "clone> server-option=hello" log &&
test_grep "clone> server-option=world" log &&
test_grep ! "clone> server-option=tar" log
'

test_expect_success 'warn if using server-option with clone with legacy protocol' ' test_expect_success 'warn if using server-option with clone with legacy protocol' '
test_when_finished "rm -rf myclone" && test_when_finished "rm -rf myclone" &&


@ -415,6 +521,23 @@ test_expect_success 'warn if using server-option with clone with legacy protocol
test_grep "server options require protocol version 2 or later" err test_grep "server options require protocol version 2 or later" err
' '


test_expect_success 'server-option configuration with legacy protocol is ok' '
test_when_finished "rm -rf myclone" &&

env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
-c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
clone "file://$(pwd)/file_parent" myclone
'

test_expect_success 'invalid server-option configuration' '
test_when_finished "rm -rf myclone" &&

test_must_fail git -c protocol.version=2 \
-c remote.origin.serverOption \
clone "file://$(pwd)/file_parent" myclone 2>err &&
test_grep "error: missing value for '\''remote.origin.serveroption'\''" err
'

test_expect_success 'upload-pack respects config using protocol v2' ' test_expect_success 'upload-pack respects config using protocol v2' '
git init server && git init server &&
write_script server/.git/hook <<-\EOF && write_script server/.git/hook <<-\EOF &&

View File

@ -334,6 +334,9 @@ static struct ref *handshake(struct transport *transport, int for_push,
data->version = discover_version(&reader); data->version = discover_version(&reader);
switch (data->version) { switch (data->version) {
case protocol_v2: case protocol_v2:
if ((!transport->server_options || !transport->server_options->nr) &&
transport->remote->server_options.nr)
transport->server_options = &transport->remote->server_options;
if (server_feature_v2("session-id", &server_sid)) if (server_feature_v2("session-id", &server_sid))
trace2_data_string("transfer", NULL, "server-sid", server_sid); trace2_data_string("transfer", NULL, "server-sid", server_sid);
if (must_list_refs) if (must_list_refs)