diff --git a/cache.h b/cache.h index be02a422d1..abbe08303e 100644 --- a/cache.h +++ b/cache.h @@ -378,6 +378,7 @@ static inline enum object_type object_type(unsigned int mode) #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE" #define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR" #define CONFIG_ENVIRONMENT "GIT_CONFIG" +#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS" #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH" #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES" #define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS" @@ -396,7 +397,7 @@ static inline enum object_type object_type(unsigned int mode) * environment creation or simple walk of the list. * The number of non-NULL entries is available as a macro. */ -#define LOCAL_REPO_ENV_SIZE 8 +#define LOCAL_REPO_ENV_SIZE 9 extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1]; extern int is_bare_repository_cfg; @@ -973,7 +974,9 @@ extern int update_server_info(int); typedef int (*config_fn_t)(const char *, const char *, void *); extern int git_default_config(const char *, const char *, void *); extern int git_config_from_file(config_fn_t fn, const char *, void *); +extern void git_config_push_parameter(const char *text); extern int git_config_parse_parameter(const char *text); +extern int git_config_parse_environment(void); extern int git_config_from_parameters(config_fn_t fn, void *data); extern int git_config(config_fn_t fn, void *); extern int git_parse_ulong(const char *, unsigned long *); diff --git a/config.c b/config.c index cdcf5836c6..c2c995f16d 100644 --- a/config.c +++ b/config.c @@ -8,6 +8,7 @@ #include "cache.h" #include "exec_cmd.h" #include "strbuf.h" +#include "quote.h" #define MAXNAME (256) @@ -34,6 +35,19 @@ static void lowercase(char *p) *p = tolower(*p); } +void git_config_push_parameter(const char *text) +{ + struct strbuf env = STRBUF_INIT; + const char *old = getenv(CONFIG_DATA_ENVIRONMENT); + if (old) { + strbuf_addstr(&env, old); + strbuf_addch(&env, ' '); + } + sq_quote_buf(&env, text); + setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1); + strbuf_release(&env); +} + int git_config_parse_parameter(const char *text) { struct config_item *ct; @@ -61,6 +75,37 @@ int git_config_parse_parameter(const char *text) return 0; } +int git_config_parse_environment(void) { + const char *env = getenv(CONFIG_DATA_ENVIRONMENT); + char *envw; + const char **argv = NULL; + int nr = 0, alloc = 0; + int i; + + if (!env) + return 0; + /* sq_dequote will write over it */ + envw = xstrdup(env); + + if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) { + free(envw); + return error("bogus format in " CONFIG_DATA_ENVIRONMENT); + } + + for (i = 0; i < nr; i++) { + if (git_config_parse_parameter(argv[i]) < 0) { + error("bogus config parameter: %s", argv[i]); + free(argv); + free(envw); + return -1; + } + } + + free(argv); + free(envw); + return 0; +} + static int get_next_char(void) { int c; @@ -773,7 +818,14 @@ int git_config_global(void) int git_config_from_parameters(config_fn_t fn, void *data) { + static int loaded_environment; const struct config_item *ct; + + if (!loaded_environment) { + if (git_config_parse_environment() < 0) + return -1; + loaded_environment = 1; + } for (ct = config_parameters; ct; ct = ct->next) if (fn(ct->name, ct->value, data) < 0) return -1; @@ -812,10 +864,9 @@ int git_config(config_fn_t fn, void *data) } free(repo_config); - if (config_parameters) { - ret += git_config_from_parameters(fn, data); + ret += git_config_from_parameters(fn, data); + if (config_parameters) found += 1; - } if (found == 0) return -1; diff --git a/environment.c b/environment.c index eeb26876a1..9425606443 100644 --- a/environment.c +++ b/environment.c @@ -73,6 +73,7 @@ static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = { ALTERNATE_DB_ENVIRONMENT, CONFIG_ENVIRONMENT, + CONFIG_DATA_ENVIRONMENT, DB_ENVIRONMENT, GIT_DIR_ENVIRONMENT, GIT_WORK_TREE_ENVIRONMENT, diff --git a/git.c b/git.c index 8de48107e0..d64ab1a24d 100644 --- a/git.c +++ b/git.c @@ -137,7 +137,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "-c expects a configuration string\n" ); usage(git_usage_string); } - git_config_parse_parameter((*argv)[1]); + git_config_push_parameter((*argv)[1]); (*argv)++; (*argc)--; } else { diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index c718253673..5bcf0b867a 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -94,6 +94,29 @@ test_expect_success 'refuse deleting push with denyDeletes' ' test_must_fail git send-pack ./victim :extra master ' +test_expect_success 'cannot override denyDeletes with git -c send-pack' ' + ( + cd victim && + test_might_fail git branch -D extra && + git config receive.denyDeletes true && + git branch extra master + ) && + test_must_fail git -c receive.denyDeletes=false \ + send-pack ./victim :extra master +' + +test_expect_success 'override denyDeletes with git -c receive-pack' ' + ( + cd victim && + test_might_fail git branch -D extra && + git config receive.denyDeletes true && + git branch extra master + ) && + git send-pack \ + --receive-pack="git -c receive.denyDeletes=false receive-pack" \ + ./victim :extra master +' + test_expect_success 'denyNonFastforwards trumps --force' ' ( cd victim &&