builtin/push.c: add push.pushOption config
Push options need to be given explicitly, via the command line as "git push --push-option <option>". Add the config option push.pushOption, which is a multi-valued option, containing push options that are sent by default. When push options are set in the lower-priority configulation file (e.g. /etc/gitconfig, or $HOME/.gitconfig), they can be unset later in the more specific repository config by the empty string. Add tests and update documentation as well. Signed-off-by: Marius Paliga <marius.paliga@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Marius Paliga committed
Oct 23, 2017 at 13:44 UTC
d8052750c5fdd53cb5a664a18ce9d78dbedb22ae
4 files changed
+135
-7
Documentation/config.txt
+29
@@ -2621,6 +2621,35 @@ push.gpgSign::
2621
override a value from a lower-priority config file. An explicit
2622
command-line flag always overrides this config option.
2623
2624
+push.pushOption::
2625
+ When no `--push-option=<option>` argument is given from the
2626
+ command line, `git push` behaves as if each <value> of
2627
+ this variable is given as `--push-option=<value>`.
2628
++
2629
+This is a multi-valued variable, and an empty value can be used in a
2630
+higher priority configuration file (e.g. `.git/config` in a
2631
+repository) to clear the values inherited from a lower priority
2632
+configuration files (e.g. `$HOME/.gitconfig`).
2633
++
2634
+--
2635
+
2636
+Example:
2637
+
2638
+/etc/gitconfig
2639
+ push.pushoption = a
2640
+ push.pushoption = b
2641
+
2642
+~/.gitconfig
2643
+ push.pushoption = c
2644
+
2645
+repo/.git/config
2646
+ push.pushoption =
2647
+ push.pushoption = b
2648
+
2649
+This will result in only b (a and c are cleared).
2650
+
2651
+--
2652
+
2653
push.recurseSubmodules::
2654
Make sure all submodule commits used by the revisions to be pushed
2655
are available on a remote-tracking branch. If the value is 'check'
Documentation/git-push.txt
+8
-2
@@ -156,11 +156,17 @@ already exists on the remote side.
156
Either all refs are updated, or on error, no refs are updated.
157
If the server does not support atomic pushes the push will fail.
158
159
--o::
160
---push-option::
159
+-o <option>::
160
+--push-option=<option>::
161
Transmit the given string to the server, which passes them to
162
the pre-receive as well as the post-receive hook. The given string
163
must not contain a NUL or LF character.
164
+ When multiple `--push-option=<option>` are given, they are
165
+ all sent to the other side in the order listed on the
166
+ command line.
167
+ When no `--push-option=<option>` is given from the command
168
+ line, the values of configuration variable `push.pushOption`
169
+ are used instead.
170
171
--receive-pack=<git-receive-pack>::
172
--exec=<git-receive-pack>::
builtin/push.c
+21
-5
@@ -32,6 +32,8 @@ static const char **refspec;
32
static int refspec_nr;
33
static int refspec_alloc;
34
35
+static struct string_list push_options_config = STRING_LIST_INIT_DUP;
36
+
37
static void add_refspec(const char *ref)
38
{
39
refspec_nr++;
@@ -503,6 +505,15 @@ static int git_push_config(const char *k, const char *v, void *cb)
505
int val = git_config_bool(k, v) ?
506
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
507
recurse_submodules = val;
508
+ } else if (!strcmp(k, "push.pushoption")) {
509
+ if (!v)
510
+ return config_error_nonbool(k);
511
+ else
512
+ if (!*v)
513
+ string_list_clear(&push_options_config, 0);
514
+ else
515
+ string_list_append(&push_options_config, v);
516
+ return 0;
517
}
518
519
return git_default_config(k, v, NULL);
@@ -515,7 +526,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
526
int push_cert = -1;
527
int rc;
528
const char *repo = NULL; /* default repository */
518
- struct string_list push_options = STRING_LIST_INIT_DUP;
529
+ struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
530
+ struct string_list *push_options;
531
const struct string_list_item *item;
532
533
struct option options[] = {
@@ -551,7 +563,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
563
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
564
PARSE_OPT_OPTARG, option_parse_push_signed },
565
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
554
- OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
566
+ OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
567
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
568
TRANSPORT_FAMILY_IPV4),
569
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@@ -562,6 +574,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
574
packet_trace_identity("push");
575
git_config(git_push_config, &flags);
576
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
577
+ push_options = (push_options_cmdline.nr
578
+ ? &push_options_cmdline
579
+ : &push_options_config);
580
set_push_cert_flags(&flags, push_cert);
581
582
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
@@ -584,12 +599,13 @@ int cmd_push(int argc, const char **argv, const char *prefix)
599
set_refspecs(argv + 1, argc - 1, repo);
600
}
601
587
- for_each_string_list_item(item, &push_options)
602
+ for_each_string_list_item(item, push_options)
603
if (strchr(item->string, '\n'))
604
die(_("push options must not have new line characters"));
605
591
- rc = do_push(repo, flags, &push_options);
592
- string_list_clear(&push_options, 0);
606
+ rc = do_push(repo, flags, push_options);
607
+ string_list_clear(&push_options_cmdline, 0);
608
+ string_list_clear(&push_options_config, 0);
609
if (rc == -1)
610
usage_with_options(push_usage, options);
611
else
t/t5545-push-options.sh
+77
@@ -140,6 +140,83 @@ test_expect_success 'push options and submodules' '
140
test_cmp expect parent_upstream/.git/hooks/post-receive.push_options
141
'
142
143
+test_expect_success 'default push option' '
144
+ mk_repo_pair &&
145
+ git -C upstream config receive.advertisePushOptions true &&
146
+ (
147
+ cd workbench &&
148
+ test_commit one &&
149
+ git push --mirror up &&
150
+ test_commit two &&
151
+ git -c push.pushOption=default push up master
152
+ ) &&
153
+ test_refs master master &&
154
+ echo "default" >expect &&
155
+ test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
156
+ test_cmp expect upstream/.git/hooks/post-receive.push_options
157
+'
158
+
159
+test_expect_success 'two default push options' '
160
+ mk_repo_pair &&
161
+ git -C upstream config receive.advertisePushOptions true &&
162
+ (
163
+ cd workbench &&
164
+ test_commit one &&
165
+ git push --mirror up &&
166
+ test_commit two &&
167
+ git -c push.pushOption=default1 -c push.pushOption=default2 push up master
168
+ ) &&
169
+ test_refs master master &&
170
+ printf "default1\ndefault2\n" >expect &&
171
+ test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
172
+ test_cmp expect upstream/.git/hooks/post-receive.push_options
173
+'
174
+
175
+test_expect_success 'push option from command line overrides from-config push option' '
176
+ mk_repo_pair &&
177
+ git -C upstream config receive.advertisePushOptions true &&
178
+ (
179
+ cd workbench &&
180
+ test_commit one &&
181
+ git push --mirror up &&
182
+ test_commit two &&
183
+ git -c push.pushOption=default push --push-option=manual up master
184
+ ) &&
185
+ test_refs master master &&
186
+ echo "manual" >expect &&
187
+ test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
188
+ test_cmp expect upstream/.git/hooks/post-receive.push_options
189
+'
190
+
191
+test_expect_success 'empty value of push.pushOption in config clears the list' '
192
+ mk_repo_pair &&
193
+ git -C upstream config receive.advertisePushOptions true &&
194
+ (
195
+ cd workbench &&
196
+ test_commit one &&
197
+ git push --mirror up &&
198
+ test_commit two &&
199
+ git -c push.pushOption=default1 -c push.pushOption= -c push.pushOption=default2 push up master
200
+ ) &&
201
+ test_refs master master &&
202
+ echo "default2" >expect &&
203
+ test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
204
+ test_cmp expect upstream/.git/hooks/post-receive.push_options
205
+'
206
+
207
+test_expect_success 'invalid push option in config' '
208
+ mk_repo_pair &&
209
+ git -C upstream config receive.advertisePushOptions true &&
210
+ (
211
+ cd workbench &&
212
+ test_commit one &&
213
+ git push --mirror up &&
214
+ test_commit two &&
215
+ test_must_fail git -c push.pushOption push up master
216
+ ) &&
217
+ test_refs master HEAD@{1}
218
+'
219
+
220
. "$TEST_DIRECTORY"/lib-httpd.sh
221
start_httpd
222