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>
This commit is contained in:
parent
4843cdefe3
commit
d8052750c5
@ -2621,6 +2621,35 @@ push.gpgSign::
|
|||||||
override a value from a lower-priority config file. An explicit
|
override a value from a lower-priority config file. An explicit
|
||||||
command-line flag always overrides this config option.
|
command-line flag always overrides this config option.
|
||||||
|
|
||||||
|
push.pushOption::
|
||||||
|
When no `--push-option=<option>` argument is given from the
|
||||||
|
command line, `git push` behaves as if each <value> of
|
||||||
|
this variable is given as `--push-option=<value>`.
|
||||||
|
+
|
||||||
|
This is a multi-valued variable, and an empty value can be used in a
|
||||||
|
higher priority configuration file (e.g. `.git/config` in a
|
||||||
|
repository) to clear the values inherited from a lower priority
|
||||||
|
configuration files (e.g. `$HOME/.gitconfig`).
|
||||||
|
+
|
||||||
|
--
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
/etc/gitconfig
|
||||||
|
push.pushoption = a
|
||||||
|
push.pushoption = b
|
||||||
|
|
||||||
|
~/.gitconfig
|
||||||
|
push.pushoption = c
|
||||||
|
|
||||||
|
repo/.git/config
|
||||||
|
push.pushoption =
|
||||||
|
push.pushoption = b
|
||||||
|
|
||||||
|
This will result in only b (a and c are cleared).
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
push.recurseSubmodules::
|
push.recurseSubmodules::
|
||||||
Make sure all submodule commits used by the revisions to be pushed
|
Make sure all submodule commits used by the revisions to be pushed
|
||||||
are available on a remote-tracking branch. If the value is 'check'
|
are available on a remote-tracking branch. If the value is 'check'
|
||||||
|
@ -156,11 +156,17 @@ already exists on the remote side.
|
|||||||
Either all refs are updated, or on error, no refs are updated.
|
Either all refs are updated, or on error, no refs are updated.
|
||||||
If the server does not support atomic pushes the push will fail.
|
If the server does not support atomic pushes the push will fail.
|
||||||
|
|
||||||
-o::
|
-o <option>::
|
||||||
--push-option::
|
--push-option=<option>::
|
||||||
Transmit the given string to the server, which passes them to
|
Transmit the given string to the server, which passes them to
|
||||||
the pre-receive as well as the post-receive hook. The given string
|
the pre-receive as well as the post-receive hook. The given string
|
||||||
must not contain a NUL or LF character.
|
must not contain a NUL or LF character.
|
||||||
|
When multiple `--push-option=<option>` are given, they are
|
||||||
|
all sent to the other side in the order listed on the
|
||||||
|
command line.
|
||||||
|
When no `--push-option=<option>` is given from the command
|
||||||
|
line, the values of configuration variable `push.pushOption`
|
||||||
|
are used instead.
|
||||||
|
|
||||||
--receive-pack=<git-receive-pack>::
|
--receive-pack=<git-receive-pack>::
|
||||||
--exec=<git-receive-pack>::
|
--exec=<git-receive-pack>::
|
||||||
|
@ -32,6 +32,8 @@ static const char **refspec;
|
|||||||
static int refspec_nr;
|
static int refspec_nr;
|
||||||
static int refspec_alloc;
|
static int refspec_alloc;
|
||||||
|
|
||||||
|
static struct string_list push_options_config = STRING_LIST_INIT_DUP;
|
||||||
|
|
||||||
static void add_refspec(const char *ref)
|
static void add_refspec(const char *ref)
|
||||||
{
|
{
|
||||||
refspec_nr++;
|
refspec_nr++;
|
||||||
@ -503,6 +505,15 @@ static int git_push_config(const char *k, const char *v, void *cb)
|
|||||||
int val = git_config_bool(k, v) ?
|
int val = git_config_bool(k, v) ?
|
||||||
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
|
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
|
||||||
recurse_submodules = val;
|
recurse_submodules = val;
|
||||||
|
} else if (!strcmp(k, "push.pushoption")) {
|
||||||
|
if (!v)
|
||||||
|
return config_error_nonbool(k);
|
||||||
|
else
|
||||||
|
if (!*v)
|
||||||
|
string_list_clear(&push_options_config, 0);
|
||||||
|
else
|
||||||
|
string_list_append(&push_options_config, v);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return git_default_config(k, v, NULL);
|
return git_default_config(k, v, NULL);
|
||||||
@ -515,7 +526,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||||||
int push_cert = -1;
|
int push_cert = -1;
|
||||||
int rc;
|
int rc;
|
||||||
const char *repo = NULL; /* default repository */
|
const char *repo = NULL; /* default repository */
|
||||||
struct string_list push_options = STRING_LIST_INIT_DUP;
|
struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
|
||||||
|
struct string_list *push_options;
|
||||||
const struct string_list_item *item;
|
const struct string_list_item *item;
|
||||||
|
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
@ -551,7 +563,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||||||
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
|
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
|
||||||
PARSE_OPT_OPTARG, option_parse_push_signed },
|
PARSE_OPT_OPTARG, option_parse_push_signed },
|
||||||
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
|
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
|
||||||
OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
|
OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
|
||||||
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
|
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
|
||||||
TRANSPORT_FAMILY_IPV4),
|
TRANSPORT_FAMILY_IPV4),
|
||||||
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
|
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)
|
|||||||
packet_trace_identity("push");
|
packet_trace_identity("push");
|
||||||
git_config(git_push_config, &flags);
|
git_config(git_push_config, &flags);
|
||||||
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
|
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
|
||||||
|
push_options = (push_options_cmdline.nr
|
||||||
|
? &push_options_cmdline
|
||||||
|
: &push_options_config);
|
||||||
set_push_cert_flags(&flags, push_cert);
|
set_push_cert_flags(&flags, push_cert);
|
||||||
|
|
||||||
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
|
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)
|
|||||||
set_refspecs(argv + 1, argc - 1, repo);
|
set_refspecs(argv + 1, argc - 1, repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_string_list_item(item, &push_options)
|
for_each_string_list_item(item, push_options)
|
||||||
if (strchr(item->string, '\n'))
|
if (strchr(item->string, '\n'))
|
||||||
die(_("push options must not have new line characters"));
|
die(_("push options must not have new line characters"));
|
||||||
|
|
||||||
rc = do_push(repo, flags, &push_options);
|
rc = do_push(repo, flags, push_options);
|
||||||
string_list_clear(&push_options, 0);
|
string_list_clear(&push_options_cmdline, 0);
|
||||||
|
string_list_clear(&push_options_config, 0);
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
usage_with_options(push_usage, options);
|
usage_with_options(push_usage, options);
|
||||||
else
|
else
|
||||||
|
@ -140,6 +140,83 @@ test_expect_success 'push options and submodules' '
|
|||||||
test_cmp expect parent_upstream/.git/hooks/post-receive.push_options
|
test_cmp expect parent_upstream/.git/hooks/post-receive.push_options
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'default push option' '
|
||||||
|
mk_repo_pair &&
|
||||||
|
git -C upstream config receive.advertisePushOptions true &&
|
||||||
|
(
|
||||||
|
cd workbench &&
|
||||||
|
test_commit one &&
|
||||||
|
git push --mirror up &&
|
||||||
|
test_commit two &&
|
||||||
|
git -c push.pushOption=default push up master
|
||||||
|
) &&
|
||||||
|
test_refs master master &&
|
||||||
|
echo "default" >expect &&
|
||||||
|
test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
|
||||||
|
test_cmp expect upstream/.git/hooks/post-receive.push_options
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'two default push options' '
|
||||||
|
mk_repo_pair &&
|
||||||
|
git -C upstream config receive.advertisePushOptions true &&
|
||||||
|
(
|
||||||
|
cd workbench &&
|
||||||
|
test_commit one &&
|
||||||
|
git push --mirror up &&
|
||||||
|
test_commit two &&
|
||||||
|
git -c push.pushOption=default1 -c push.pushOption=default2 push up master
|
||||||
|
) &&
|
||||||
|
test_refs master master &&
|
||||||
|
printf "default1\ndefault2\n" >expect &&
|
||||||
|
test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
|
||||||
|
test_cmp expect upstream/.git/hooks/post-receive.push_options
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'push option from command line overrides from-config push option' '
|
||||||
|
mk_repo_pair &&
|
||||||
|
git -C upstream config receive.advertisePushOptions true &&
|
||||||
|
(
|
||||||
|
cd workbench &&
|
||||||
|
test_commit one &&
|
||||||
|
git push --mirror up &&
|
||||||
|
test_commit two &&
|
||||||
|
git -c push.pushOption=default push --push-option=manual up master
|
||||||
|
) &&
|
||||||
|
test_refs master master &&
|
||||||
|
echo "manual" >expect &&
|
||||||
|
test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
|
||||||
|
test_cmp expect upstream/.git/hooks/post-receive.push_options
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'empty value of push.pushOption in config clears the list' '
|
||||||
|
mk_repo_pair &&
|
||||||
|
git -C upstream config receive.advertisePushOptions true &&
|
||||||
|
(
|
||||||
|
cd workbench &&
|
||||||
|
test_commit one &&
|
||||||
|
git push --mirror up &&
|
||||||
|
test_commit two &&
|
||||||
|
git -c push.pushOption=default1 -c push.pushOption= -c push.pushOption=default2 push up master
|
||||||
|
) &&
|
||||||
|
test_refs master master &&
|
||||||
|
echo "default2" >expect &&
|
||||||
|
test_cmp expect upstream/.git/hooks/pre-receive.push_options &&
|
||||||
|
test_cmp expect upstream/.git/hooks/post-receive.push_options
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'invalid push option in config' '
|
||||||
|
mk_repo_pair &&
|
||||||
|
git -C upstream config receive.advertisePushOptions true &&
|
||||||
|
(
|
||||||
|
cd workbench &&
|
||||||
|
test_commit one &&
|
||||||
|
git push --mirror up &&
|
||||||
|
test_commit two &&
|
||||||
|
test_must_fail git -c push.pushOption push up master
|
||||||
|
) &&
|
||||||
|
test_refs master HEAD@{1}
|
||||||
|
'
|
||||||
|
|
||||||
. "$TEST_DIRECTORY"/lib-httpd.sh
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||||
start_httpd
|
start_httpd
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user