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 Changing or clearing this value will only affect fetches for new commits. 97 To fetch associated objects for commits already present in the local object 98 database, use the `--refetch` option of linkgit:git-fetch[1].
··· 96 Changing or clearing this value will only affect fetches for new commits. 97 To fetch associated objects for commits already present in the local object 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 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 309 --show-forced-updates:: 310 By default, git checks if a branch is force-updated during
··· 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
+3
Documentation/git-clone.txt
··· 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 153 `-n`:: 154 `--no-checkout`::
··· 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`::
+3
Documentation/git-ls-remote.txt
··· 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 85 <repository>:: 86 The "remote" repository to query. This parameter can be
··· 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
+2
builtin/fetch.c
··· 1981 strvec_pushl(&argv, "-c", "fetch.bundleURI=", 1982 "fetch", "--append", "--no-auto-gc", 1983 "--no-write-commit-graph", NULL); 1984 add_options_to_argv(&argv, config); 1985 1986 if (max_children != 1 && list->nr != 1) {
··· 1981 strvec_pushl(&argv, "-c", "fetch.bundleURI=", 1982 "fetch", "--append", "--no-auto-gc", 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); 1986 add_options_to_argv(&argv, config); 1987 1988 if (max_children != 1 && list->nr != 1) {
+1
builtin/ls-remote.c
··· 173 transport_ls_refs_options_release(&transport_options); 174 175 strvec_clear(&pattern); 176 return status; 177 }
··· 173 transport_ls_refs_options_release(&transport_options); 174 175 strvec_clear(&pattern); 176 + string_list_clear(&server_options, 0); 177 return status; 178 }
+1 -8
builtin/push.c
··· 519 RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; 520 recurse_submodules = val; 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; 530 } else if (!strcmp(k, "color.push")) { 531 push_use_color = git_config_colorbool(k, v); 532 return 0;
··· 519 RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; 520 recurse_submodules = val; 521 } else if (!strcmp(k, "push.pushoption")) { 522 + return parse_transport_option(k, v, &push_options_config); 523 } else if (!strcmp(k, "color.push")) { 524 push_use_color = git_config_colorbool(k, v); 525 return 0;
+6
remote.c
··· 24 #include "advice.h" 25 #include "connect.h" 26 #include "parse-options.h" 27 28 enum map_direction { FROM_SRC, FROM_DST }; 29 ··· 143 ret->name = xstrndup(name, len); 144 refspec_init(&ret->push, REFSPEC_PUSH); 145 refspec_init(&ret->fetch, REFSPEC_FETCH); 146 147 ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1, 148 remote_state->remotes_alloc); ··· 166 free((char *)remote->uploadpack); 167 FREE_AND_NULL(remote->http_proxy); 168 FREE_AND_NULL(remote->http_proxy_authmethod); 169 } 170 171 static void add_merge(struct branch *branch, const char *name) ··· 508 } else if (!strcmp(subkey, "vcs")) { 509 FREE_AND_NULL(remote->foreign_vcs); 510 return git_config_string(&remote->foreign_vcs, key, value); 511 } 512 return 0; 513 }
··· 24 #include "advice.h" 25 #include "connect.h" 26 #include "parse-options.h" 27 + #include "transport.h" 28 29 enum map_direction { FROM_SRC, FROM_DST }; 30 ··· 144 ret->name = xstrndup(name, len); 145 refspec_init(&ret->push, REFSPEC_PUSH); 146 refspec_init(&ret->fetch, REFSPEC_FETCH); 147 + string_list_init_dup(&ret->server_options); 148 149 ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1, 150 remote_state->remotes_alloc); ··· 168 free((char *)remote->uploadpack); 169 FREE_AND_NULL(remote->http_proxy); 170 FREE_AND_NULL(remote->http_proxy_authmethod); 171 + string_list_clear(&remote->server_options, 0); 172 } 173 174 static void add_merge(struct branch *branch, const char *name) ··· 511 } else if (!strcmp(subkey, "vcs")) { 512 FREE_AND_NULL(remote->foreign_vcs); 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); 517 } 518 return 0; 519 }
+3
remote.h
··· 4 #include "hash.h" 5 #include "hashmap.h" 6 #include "refspec.h" 7 #include "strvec.h" 8 9 struct option; ··· 104 105 /* The method used for authenticating against `http_proxy`. */ 106 char *http_proxy_authmethod; 107 }; 108 109 /**
··· 4 #include "hash.h" 5 #include "hashmap.h" 6 #include "refspec.h" 7 + #include "string-list.h" 8 #include "strvec.h" 9 10 struct option; ··· 105 106 /* The method used for authenticating against `http_proxy`. */ 107 char *http_proxy_authmethod; 108 + 109 + struct string_list server_options; 110 }; 111 112 /**
+133
t/t5702-protocol-v2.sh
··· 185 grep "server-option=world" log 186 ' 187 188 test_expect_success 'warn if using server-option with ls-remote with legacy protocol' ' 189 test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \ 190 ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err && ··· 381 grep "server-option=world" log 382 ' 383 384 test_expect_success 'warn if using server-option with fetch with legacy protocol' ' 385 test_when_finished "rm -rf temp_child" && 386 ··· 404 grep "server-option=world" log 405 ' 406 407 test_expect_success 'warn if using server-option with clone with legacy protocol' ' 408 test_when_finished "rm -rf myclone" && 409 ··· 413 414 test_grep "see protocol.version in" err && 415 test_grep "server options require protocol version 2 or later" err 416 ' 417 418 test_expect_success 'upload-pack respects config using protocol v2' '
··· 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 && ··· 418 grep "server-option=world" log 419 ' 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 + 469 test_expect_success 'warn if using server-option with fetch with legacy protocol' ' 470 test_when_finished "rm -rf temp_child" && 471 ··· 489 grep "server-option=world" log 490 ' 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 + 523 test_expect_success 'warn if using server-option with clone with legacy protocol' ' 524 test_when_finished "rm -rf myclone" && 525 ··· 529 530 test_grep "see protocol.version in" err && 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 549 ' 550 551 test_expect_success 'upload-pack respects config using protocol v2' '
+15
transport.c
··· 334 data->version = discover_version(&reader); 335 switch (data->version) { 336 case protocol_v2: 337 if (server_feature_v2("session-id", &server_sid)) 338 trace2_data_string("transfer", NULL, "server-sid", server_sid); 339 if (must_list_refs) ··· 1106 } 1107 1108 BUG("invalid protocol_allow_config type"); 1109 } 1110 1111 void transport_check_allowed(const char *type)
··· 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) ··· 1109 } 1110 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; 1124 } 1125 1126 void transport_check_allowed(const char *type)
+4
transport.h
··· 342 /* common method used by transport-helper.c and send-pack.c */ 343 void reject_atomic_push(struct ref *refs, int mirror_mode); 344 345 #endif
··· 342 /* common method used by transport-helper.c and send-pack.c */ 343 void reject_atomic_push(struct ref *refs, int mirror_mode); 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 + 349 #endif