Git fork

Merge branch 'xx/remote-server-option-config'

A new configuration variable remote.<name>.serverOption makes the
transport layer act as if the --serverOption=<value> option is
given from the command line.

* xx/remote-server-option-config:
ls-remote: leakfix for not clearing server_options
fetch: respect --server-option when fetching multiple remotes
transport.c::handshake: make use of server options from remote
remote: introduce remote.<name>.serverOption configuration
transport: introduce parse_transport_option() method

+184 -8
+10
Documentation/config/remote.txt
··· 96 96 Changing or clearing this value will only affect fetches for new commits. 97 97 To fetch associated objects for commits already present in the local object 98 98 database, use the `--refetch` option of linkgit:git-fetch[1]. 99 + 100 + remote.<name>.serverOption:: 101 + The default set of server options used when fetching from this remote. 102 + These server options can be overridden by the `--server-option=` command 103 + line arguments. 104 + + 105 + This is a multi-valued variable, and an empty value can be used in a higher 106 + priority configuration file (e.g. `.git/config` in a repository) to clear 107 + the values inherited from a lower priority configuration files (e.g. 108 + `$HOME/.gitconfig`).
+3
Documentation/fetch-options.txt
··· 305 305 unknown ones, is server-specific. 306 306 When multiple `--server-option=<option>` are given, they are all 307 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. 308 311 309 312 --show-forced-updates:: 310 313 By default, git checks if a branch is force-updated during
+3
Documentation/git-clone.txt
··· 149 149 unknown ones, is server-specific. 150 150 When multiple `--server-option=<option>` are given, they are all 151 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. 152 155 153 156 `-n`:: 154 157 `--no-checkout`::
+3
Documentation/git-ls-remote.txt
··· 81 81 character. 82 82 When multiple `--server-option=<option>` are given, they are all 83 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. 84 87 85 88 <repository>:: 86 89 The "remote" repository to query. This parameter can be
+2
builtin/fetch.c
··· 1981 1981 strvec_pushl(&argv, "-c", "fetch.bundleURI=", 1982 1982 "fetch", "--append", "--no-auto-gc", 1983 1983 "--no-write-commit-graph", NULL); 1984 + for (i = 0; i < server_options.nr; i++) 1985 + strvec_pushf(&argv, "--server-option=%s", server_options.items[i].string); 1984 1986 add_options_to_argv(&argv, config); 1985 1987 1986 1988 if (max_children != 1 && list->nr != 1) {
+1
builtin/ls-remote.c
··· 173 173 transport_ls_refs_options_release(&transport_options); 174 174 175 175 strvec_clear(&pattern); 176 + string_list_clear(&server_options, 0); 176 177 return status; 177 178 }
+1 -8
builtin/push.c
··· 519 519 RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; 520 520 recurse_submodules = val; 521 521 } else if (!strcmp(k, "push.pushoption")) { 522 - if (!v) 523 - return config_error_nonbool(k); 524 - else 525 - if (!*v) 526 - string_list_clear(&push_options_config, 0); 527 - else 528 - string_list_append(&push_options_config, v); 529 - return 0; 522 + return parse_transport_option(k, v, &push_options_config); 530 523 } else if (!strcmp(k, "color.push")) { 531 524 push_use_color = git_config_colorbool(k, v); 532 525 return 0;
+6
remote.c
··· 24 24 #include "advice.h" 25 25 #include "connect.h" 26 26 #include "parse-options.h" 27 + #include "transport.h" 27 28 28 29 enum map_direction { FROM_SRC, FROM_DST }; 29 30 ··· 143 144 ret->name = xstrndup(name, len); 144 145 refspec_init(&ret->push, REFSPEC_PUSH); 145 146 refspec_init(&ret->fetch, REFSPEC_FETCH); 147 + string_list_init_dup(&ret->server_options); 146 148 147 149 ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1, 148 150 remote_state->remotes_alloc); ··· 166 168 free((char *)remote->uploadpack); 167 169 FREE_AND_NULL(remote->http_proxy); 168 170 FREE_AND_NULL(remote->http_proxy_authmethod); 171 + string_list_clear(&remote->server_options, 0); 169 172 } 170 173 171 174 static void add_merge(struct branch *branch, const char *name) ··· 508 511 } else if (!strcmp(subkey, "vcs")) { 509 512 FREE_AND_NULL(remote->foreign_vcs); 510 513 return git_config_string(&remote->foreign_vcs, key, value); 514 + } else if (!strcmp(subkey, "serveroption")) { 515 + return parse_transport_option(key, value, 516 + &remote->server_options); 511 517 } 512 518 return 0; 513 519 }
+3
remote.h
··· 4 4 #include "hash.h" 5 5 #include "hashmap.h" 6 6 #include "refspec.h" 7 + #include "string-list.h" 7 8 #include "strvec.h" 8 9 9 10 struct option; ··· 104 105 105 106 /* The method used for authenticating against `http_proxy`. */ 106 107 char *http_proxy_authmethod; 108 + 109 + struct string_list server_options; 107 110 }; 108 111 109 112 /**
+133
t/t5702-protocol-v2.sh
··· 185 185 grep "server-option=world" log 186 186 ' 187 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 + 188 225 test_expect_success 'warn if using server-option with ls-remote with legacy protocol' ' 189 226 test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \ 190 227 ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err && ··· 381 418 grep "server-option=world" log 382 419 ' 383 420 421 + test_expect_success 'server-options are sent when fetch multiple remotes' ' 422 + test_when_finished "rm -f log server_options_sent" && 423 + git clone "file://$(pwd)/file_parent" child_multi_remotes && 424 + git -C child_multi_remotes remote add another "file://$(pwd)/file_parent" && 425 + GIT_TRACE_PACKET="$(pwd)/log" git -C child_multi_remotes -c protocol.version=2 \ 426 + fetch -o hello --all && 427 + grep "fetch> server-option=hello" log >server_options_sent && 428 + test_line_count = 2 server_options_sent 429 + ' 430 + 431 + test_expect_success 'server-options from configuration are used by git-fetch' ' 432 + test_when_finished "rm -rf log myclone" && 433 + git clone "file://$(pwd)/file_parent" myclone && 434 + git -C file_parent log -1 --format=%s >expect && 435 + 436 + # Default server options from configuration are used 437 + git -C myclone config --add remote.origin.serverOption foo && 438 + git -C myclone config --add remote.origin.serverOption bar && 439 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \ 440 + fetch origin main && 441 + git -C myclone log -1 --format=%s origin/main >actual && 442 + test_cmp expect actual && 443 + test_grep "fetch> server-option=foo" log && 444 + test_grep "fetch> server-option=bar" log && 445 + rm -f log && 446 + 447 + # Empty value of remote.<name>.serverOption clears the list 448 + git -C myclone config --add remote.origin.serverOption "" && 449 + git -C myclone config --add remote.origin.serverOption tar && 450 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \ 451 + fetch origin main && 452 + git -C myclone log -1 --format=%s origin/main >actual && 453 + test_cmp expect actual && 454 + test_grep "fetch> server-option=tar" log && 455 + test_grep ! "fetch> server-option=foo" log && 456 + test_grep ! "fetch> server-option=bar" log && 457 + rm -f log && 458 + 459 + # Server option from command line overrides those from configuration 460 + GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \ 461 + fetch -o hello -o world origin main && 462 + git -C myclone log -1 --format=%s origin/main >actual && 463 + test_cmp expect actual && 464 + test_grep "fetch> server-option=hello" log && 465 + test_grep "fetch> server-option=world" log && 466 + test_grep ! "fetch> server-option=tar" log 467 + ' 468 + 384 469 test_expect_success 'warn if using server-option with fetch with legacy protocol' ' 385 470 test_when_finished "rm -rf temp_child" && 386 471 ··· 404 489 grep "server-option=world" log 405 490 ' 406 491 492 + test_expect_success 'server-options from configuration are used by git-clone' ' 493 + test_when_finished "rm -rf log myclone" && 494 + 495 + # Default server options from configuration are used 496 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \ 497 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \ 498 + clone "file://$(pwd)/file_parent" myclone && 499 + test_grep "clone> server-option=foo" log && 500 + test_grep "clone> server-option=bar" log && 501 + rm -rf log myclone && 502 + 503 + # Empty value of remote.<name>.serverOption clears the list 504 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \ 505 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \ 506 + -c remote.origin.serverOption= -c remote.origin.serverOption=tar \ 507 + clone "file://$(pwd)/file_parent" myclone && 508 + test_grep "clone> server-option=tar" log && 509 + test_grep ! "clone> server-option=foo" log && 510 + test_grep ! "clone> server-option=bar" log && 511 + rm -rf log myclone && 512 + 513 + # Server option from command line overrides those from configuration 514 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \ 515 + -c remote.origin.serverOption=tar \ 516 + clone --server-option=hello --server-option=world \ 517 + "file://$(pwd)/file_parent" myclone && 518 + test_grep "clone> server-option=hello" log && 519 + test_grep "clone> server-option=world" log && 520 + test_grep ! "clone> server-option=tar" log 521 + ' 522 + 407 523 test_expect_success 'warn if using server-option with clone with legacy protocol' ' 408 524 test_when_finished "rm -rf myclone" && 409 525 ··· 413 529 414 530 test_grep "see protocol.version in" err && 415 531 test_grep "server options require protocol version 2 or later" err 532 + ' 533 + 534 + test_expect_success 'server-option configuration with legacy protocol is ok' ' 535 + test_when_finished "rm -rf myclone" && 536 + 537 + env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \ 538 + -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \ 539 + clone "file://$(pwd)/file_parent" myclone 540 + ' 541 + 542 + test_expect_success 'invalid server-option configuration' ' 543 + test_when_finished "rm -rf myclone" && 544 + 545 + test_must_fail git -c protocol.version=2 \ 546 + -c remote.origin.serverOption \ 547 + clone "file://$(pwd)/file_parent" myclone 2>err && 548 + test_grep "error: missing value for '\''remote.origin.serveroption'\''" err 416 549 ' 417 550 418 551 test_expect_success 'upload-pack respects config using protocol v2' '
+15
transport.c
··· 334 334 data->version = discover_version(&reader); 335 335 switch (data->version) { 336 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; 337 340 if (server_feature_v2("session-id", &server_sid)) 338 341 trace2_data_string("transfer", NULL, "server-sid", server_sid); 339 342 if (must_list_refs) ··· 1106 1109 } 1107 1110 1108 1111 BUG("invalid protocol_allow_config type"); 1112 + } 1113 + 1114 + int parse_transport_option(const char *var, const char *value, 1115 + struct string_list *transport_options) 1116 + { 1117 + if (!value) 1118 + return config_error_nonbool(var); 1119 + if (!*value) 1120 + string_list_clear(transport_options, 0); 1121 + else 1122 + string_list_append(transport_options, value); 1123 + return 0; 1109 1124 } 1110 1125 1111 1126 void transport_check_allowed(const char *type)
+4
transport.h
··· 342 342 /* common method used by transport-helper.c and send-pack.c */ 343 343 void reject_atomic_push(struct ref *refs, int mirror_mode); 344 344 345 + /* common method to parse push-option or server-option from config */ 346 + int parse_transport_option(const char *var, const char *value, 347 + struct string_list *transport_options); 348 + 345 349 #endif