transport.c::handshake: 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>

Xing Xin committed Oct 8, 2024 at 03:38 UTC 094f78a16a6c150ff125afd9c3f2773b47384c06
5 files changed +135
Documentation/fetch-options.txt
+3
@@ -305,6 +305,9 @@ endif::git-pull[]
305 unknown ones, is server-specific.
306 When multiple `--server-option=<option>` are given, they are all
307 sent to the other side in the order listed on the command line.
308 + When no `--server-option=<option>` is given from the command line,
309 + the values of configuration variable `remote.<name>.serverOption`
310 + are used instead.
311
312 --show-forced-updates::
313 By default, git checks if a branch is force-updated during
Documentation/git-clone.txt
+3
@@ -149,6 +149,9 @@ objects from the source repository into a pack in the cloned repository.
149 unknown ones, is server-specific.
150 When multiple ++--server-option=++__<option>__ are given, they are all
151 sent to the other side in the order listed on the command line.
152 + When no ++--server-option=++__<option>__ is given from the command
153 + line, the values of configuration variable `remote.<name>.serverOption`
154 + are used instead.
155
156 `-n`::
157 `--no-checkout`::
Documentation/git-ls-remote.txt
+3
@@ -81,6 +81,9 @@ OPTIONS
81 character.
82 When multiple `--server-option=<option>` are given, they are all
83 sent to the other side in the order listed on the command line.
84 + When no `--server-option=<option>` is given from the command line,
85 + the values of configuration variable `remote.<name>.serverOption`
86 + are used instead.
87
88 <repository>::
89 The "remote" repository to query. This parameter can be
t/t5702-protocol-v2.sh
+123
@@ -185,6 +185,43 @@ test_expect_success 'server-options are sent when using ls-remote' '
185 grep "server-option=world" log
186 '
187
188 +test_expect_success 'server-options from configuration are used by ls-remote' '
189 + test_when_finished "rm -rf log myclone" &&
190 + git clone "file://$(pwd)/file_parent" myclone &&
191 + cat >expect <<-EOF &&
192 + $(git -C file_parent rev-parse refs/heads/main)$(printf "\t")refs/heads/main
193 + EOF
194 +
195 + # Default server options from configuration are used
196 + git -C myclone config --add remote.origin.serverOption foo &&
197 + git -C myclone config --add remote.origin.serverOption bar &&
198 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
199 + ls-remote origin main >actual &&
200 + test_cmp expect actual &&
201 + test_grep "ls-remote> server-option=foo" log &&
202 + test_grep "ls-remote> server-option=bar" log &&
203 + rm -f log &&
204 +
205 + # Empty value of remote.<name>.serverOption clears the list
206 + git -C myclone config --add remote.origin.serverOption "" &&
207 + git -C myclone config --add remote.origin.serverOption tar &&
208 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
209 + ls-remote origin main >actual &&
210 + test_cmp expect actual &&
211 + test_grep "ls-remote> server-option=tar" log &&
212 + test_grep ! "ls-remote> server-option=foo" log &&
213 + test_grep ! "ls-remote> server-option=bar" log &&
214 + rm -f log &&
215 +
216 + # Server option from command line overrides those from configuration
217 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
218 + ls-remote -o hello -o world origin main >actual &&
219 + test_cmp expect actual &&
220 + test_grep "ls-remote> server-option=hello" log &&
221 + test_grep "ls-remote> server-option=world" log &&
222 + test_grep ! "ls-remote> server-option=tar" log
223 +'
224 +
225 test_expect_success 'warn if using server-option with ls-remote with legacy protocol' '
226 test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
227 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' '
418 grep "server-option=world" log
419 '
420
421 +test_expect_success 'server-options from configuration are used by git-fetch' '
422 + test_when_finished "rm -rf log myclone" &&
423 + git clone "file://$(pwd)/file_parent" myclone &&
424 + git -C file_parent log -1 --format=%s >expect &&
425 +
426 + # Default server options from configuration are used
427 + git -C myclone config --add remote.origin.serverOption foo &&
428 + git -C myclone config --add remote.origin.serverOption bar &&
429 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
430 + fetch origin main &&
431 + git -C myclone log -1 --format=%s origin/main >actual &&
432 + test_cmp expect actual &&
433 + test_grep "fetch> server-option=foo" log &&
434 + test_grep "fetch> server-option=bar" log &&
435 + rm -f log &&
436 +
437 + # Empty value of remote.<name>.serverOption clears the list
438 + git -C myclone config --add remote.origin.serverOption "" &&
439 + git -C myclone config --add remote.origin.serverOption tar &&
440 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
441 + fetch origin main &&
442 + git -C myclone log -1 --format=%s origin/main >actual &&
443 + test_cmp expect actual &&
444 + test_grep "fetch> server-option=tar" log &&
445 + test_grep ! "fetch> server-option=foo" log &&
446 + test_grep ! "fetch> server-option=bar" log &&
447 + rm -f log &&
448 +
449 + # Server option from command line overrides those from configuration
450 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
451 + fetch -o hello -o world origin main &&
452 + git -C myclone log -1 --format=%s origin/main >actual &&
453 + test_cmp expect actual &&
454 + test_grep "fetch> server-option=hello" log &&
455 + test_grep "fetch> server-option=world" log &&
456 + test_grep ! "fetch> server-option=tar" log
457 +'
458 +
459 test_expect_success 'warn if using server-option with fetch with legacy protocol' '
460 test_when_finished "rm -rf temp_child" &&
461
@@ -404,6 +479,37 @@ test_expect_success 'server-options are sent when cloning' '
479 grep "server-option=world" log
480 '
481
482 +test_expect_success 'server-options from configuration are used by git-clone' '
483 + test_when_finished "rm -rf log myclone" &&
484 +
485 + # Default server options from configuration are used
486 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
487 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
488 + clone "file://$(pwd)/file_parent" myclone &&
489 + test_grep "clone> server-option=foo" log &&
490 + test_grep "clone> server-option=bar" log &&
491 + rm -rf log myclone &&
492 +
493 + # Empty value of remote.<name>.serverOption clears the list
494 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
495 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
496 + -c remote.origin.serverOption= -c remote.origin.serverOption=tar \
497 + clone "file://$(pwd)/file_parent" myclone &&
498 + test_grep "clone> server-option=tar" log &&
499 + test_grep ! "clone> server-option=foo" log &&
500 + test_grep ! "clone> server-option=bar" log &&
501 + rm -rf log myclone &&
502 +
503 + # Server option from command line overrides those from configuration
504 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
505 + -c remote.origin.serverOption=tar \
506 + clone --server-option=hello --server-option=world \
507 + "file://$(pwd)/file_parent" myclone &&
508 + test_grep "clone> server-option=hello" log &&
509 + test_grep "clone> server-option=world" log &&
510 + test_grep ! "clone> server-option=tar" log
511 +'
512 +
513 test_expect_success 'warn if using server-option with clone with legacy protocol' '
514 test_when_finished "rm -rf myclone" &&
515
@@ -415,6 +521,23 @@ test_expect_success 'warn if using server-option with clone with legacy protocol
521 test_grep "server options require protocol version 2 or later" err
522 '
523
524 +test_expect_success 'server-option configuration with legacy protocol is ok' '
525 + test_when_finished "rm -rf myclone" &&
526 +
527 + env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
528 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
529 + clone "file://$(pwd)/file_parent" myclone
530 +'
531 +
532 +test_expect_success 'invalid server-option configuration' '
533 + test_when_finished "rm -rf myclone" &&
534 +
535 + test_must_fail git -c protocol.version=2 \
536 + -c remote.origin.serverOption \
537 + clone "file://$(pwd)/file_parent" myclone 2>err &&
538 + test_grep "error: missing value for '\''remote.origin.serveroption'\''" err
539 +'
540 +
541 test_expect_success 'upload-pack respects config using protocol v2' '
542 git init server &&
543 write_script server/.git/hook <<-\EOF &&
transport.c
+3
@@ -334,6 +334,9 @@ static struct ref *handshake(struct transport *transport, int for_push,
334 data->version = discover_version(&reader);
335 switch (data->version) {
336 case protocol_v2:
337 + if ((!transport->server_options || !transport->server_options->nr) &&
338 + transport->remote->server_options.nr)
339 + transport->server_options = &transport->remote->server_options;
340 if (server_feature_v2("session-id", &server_sid))
341 trace2_data_string("transfer", NULL, "server-sid", server_sid);
342 if (must_list_refs)