Skip to content

Commit fd98f65

Browse files
committed
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
2 parents 8a5545b + 0f490d2 commit fd98f65

File tree

12 files changed

+184
-8
lines changed

12 files changed

+184
-8
lines changed

Documentation/config/remote.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,13 @@ remote.<name>.partialclonefilter::
9696
Changing or clearing this value will only affect fetches for new commits.
9797
To fetch associated objects for commits already present in the local object
9898
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`).

Documentation/fetch-options.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ endif::git-pull[]
305305
unknown ones, is server-specific.
306306
When multiple `--server-option=<option>` are given, they are all
307307
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.
308311

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

Documentation/git-clone.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ objects from the source repository into a pack in the cloned repository.
149149
unknown ones, is server-specific.
150150
When multiple `--server-option=<option>` are given, they are all
151151
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.
152155

153156
`-n`::
154157
`--no-checkout`::

Documentation/git-ls-remote.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ OPTIONS
8181
character.
8282
When multiple `--server-option=<option>` are given, they are all
8383
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.
8487

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

builtin/fetch.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,6 +1981,8 @@ static int fetch_multiple(struct string_list *list, int max_children,
19811981
strvec_pushl(&argv, "-c", "fetch.bundleURI=",
19821982
"fetch", "--append", "--no-auto-gc",
19831983
"--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);
19841986
add_options_to_argv(&argv, config);
19851987

19861988
if (max_children != 1 && list->nr != 1) {

builtin/ls-remote.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,5 +173,6 @@ int cmd_ls_remote(int argc,
173173
transport_ls_refs_options_release(&transport_options);
174174

175175
strvec_clear(&pattern);
176+
string_list_clear(&server_options, 0);
176177
return status;
177178
}

builtin/push.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -519,14 +519,7 @@ static int git_push_config(const char *k, const char *v,
519519
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
520520
recurse_submodules = val;
521521
} 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);
530523
} else if (!strcmp(k, "color.push")) {
531524
push_use_color = git_config_colorbool(k, v);
532525
return 0;

remote.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "advice.h"
2525
#include "connect.h"
2626
#include "parse-options.h"
27+
#include "transport.h"
2728

2829
enum map_direction { FROM_SRC, FROM_DST };
2930

@@ -143,6 +144,7 @@ static struct remote *make_remote(struct remote_state *remote_state,
143144
ret->name = xstrndup(name, len);
144145
refspec_init(&ret->push, REFSPEC_PUSH);
145146
refspec_init(&ret->fetch, REFSPEC_FETCH);
147+
string_list_init_dup(&ret->server_options);
146148

147149
ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1,
148150
remote_state->remotes_alloc);
@@ -166,6 +168,7 @@ static void remote_clear(struct remote *remote)
166168
free((char *)remote->uploadpack);
167169
FREE_AND_NULL(remote->http_proxy);
168170
FREE_AND_NULL(remote->http_proxy_authmethod);
171+
string_list_clear(&remote->server_options, 0);
169172
}
170173

171174
static void add_merge(struct branch *branch, const char *name)
@@ -508,6 +511,9 @@ static int handle_config(const char *key, const char *value,
508511
} else if (!strcmp(subkey, "vcs")) {
509512
FREE_AND_NULL(remote->foreign_vcs);
510513
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);
511517
}
512518
return 0;
513519
}

remote.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "hash.h"
55
#include "hashmap.h"
66
#include "refspec.h"
7+
#include "string-list.h"
78
#include "strvec.h"
89

910
struct option;
@@ -104,6 +105,8 @@ struct remote {
104105

105106
/* The method used for authenticating against `http_proxy`. */
106107
char *http_proxy_authmethod;
108+
109+
struct string_list server_options;
107110
};
108111

109112
/**

t/t5702-protocol-v2.sh

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,43 @@ test_expect_success 'server-options are sent when using ls-remote' '
185185
grep "server-option=world" log
186186
'
187187

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+
188225
test_expect_success 'warn if using server-option with ls-remote with legacy protocol' '
189226
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
190227
ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err &&
@@ -381,6 +418,54 @@ test_expect_success 'server-options are sent when fetching' '
381418
grep "server-option=world" log
382419
'
383420

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+
384469
test_expect_success 'warn if using server-option with fetch with legacy protocol' '
385470
test_when_finished "rm -rf temp_child" &&
386471
@@ -404,6 +489,37 @@ test_expect_success 'server-options are sent when cloning' '
404489
grep "server-option=world" log
405490
'
406491

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+
407523
test_expect_success 'warn if using server-option with clone with legacy protocol' '
408524
test_when_finished "rm -rf myclone" &&
409525
@@ -415,6 +531,23 @@ test_expect_success 'warn if using server-option with clone with legacy protocol
415531
test_grep "server options require protocol version 2 or later" err
416532
'
417533

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+
418551
test_expect_success 'upload-pack respects config using protocol v2' '
419552
git init server &&
420553
write_script server/.git/hook <<-\EOF &&

transport.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ static struct ref *handshake(struct transport *transport, int for_push,
334334
data->version = discover_version(&reader);
335335
switch (data->version) {
336336
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;
337340
if (server_feature_v2("session-id", &server_sid))
338341
trace2_data_string("transfer", NULL, "server-sid", server_sid);
339342
if (must_list_refs)
@@ -1108,6 +1111,18 @@ int is_transport_allowed(const char *type, int from_user)
11081111
BUG("invalid protocol_allow_config type");
11091112
}
11101113

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+
11111126
void transport_check_allowed(const char *type)
11121127
{
11131128
if (!is_transport_allowed(type, -1))

transport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,4 +342,8 @@ void transport_print_push_status(const char *dest, struct ref *refs,
342342
/* common method used by transport-helper.c and send-pack.c */
343343
void reject_atomic_push(struct ref *refs, int mirror_mode);
344344

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+
345349
#endif

0 commit comments

Comments
 (0)