The problem lies with the regexp used for simulating --add in `git_config_set_multivar_in_file()`, "^$", which in ideal case should not match with any string but is true for empty strings. Instead use a sentinel value CONFIG_REGEX_NONE to say "we do not want to replace any existing entry" and use it in the implementation of "git config --add". For removing the segfault add a check for NULL values in `matches()` in config.c. Helped-by: Junio C Hamano <gitster@xxxxxxxxx> Signed-off-by: Tanay Abhra <tanayabh@xxxxxxxxx> --- builtin/config.c | 2 +- cache.h | 2 ++ config.c | 21 +++++++++++++++++---- t/t1303-wacky-config.sh | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index aba7135..195664b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -611,7 +611,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar_in_file(given_config_source.file, - argv[0], value, "^$", 0); + argv[0], value, CONFIG_REGEX_NONE, 0); } else if (actions == ACTION_REPLACE_ALL) { check_write(); diff --git a/cache.h b/cache.h index dfa1a56..a09217d 100644 --- a/cache.h +++ b/cache.h @@ -1284,6 +1284,8 @@ extern int update_server_info(int); #define CONFIG_INVALID_PATTERN 6 #define CONFIG_GENERIC_ERROR 7 +extern const char CONFIG_REGEX_NONE[]; + struct git_config_source { unsigned int use_stdin:1; const char *file; diff --git a/config.c b/config.c index 83c913a..20476e0 100644 --- a/config.c +++ b/config.c @@ -46,6 +46,8 @@ static int zlib_compression_seen; */ static struct config_set the_config_set; +const char CONFIG_REGEX_NONE[] = "a^"; + static int config_file_fgetc(struct config_source *conf) { return fgetc(conf->u.file); @@ -1607,14 +1609,20 @@ static struct { unsigned int offset_alloc; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; int seen; + unsigned value_never_matches:1; } store; static int matches(const char *key, const char *value) { - return !strcmp(key, store.key) && - (store.value_regex == NULL || - (store.do_not_match ^ - !regexec(store.value_regex, value, 0, NULL, 0))); + if (strcmp(key, store.key)) + return 0; /* not ours */ + if (!store.value_regex) + return 1; /* always matches */ + if (store.value_never_matches) + return 0; /* never matches */ + + return store.do_not_match ^ + (value && !regexec(store.value_regex, value, 0, NULL, 0)); } static int store_aux(const char *key, const char *value, void *cb) @@ -1876,6 +1884,8 @@ out_free_ret_1: /* * If value==NULL, unset in (remove from) config, * if value_regex!=NULL, disregard key/value pairs where value does not match. + * if value_regex==CONFIG_REGEX_NONE, do not match any existing values + * (only add a new one) * if multi_replace==0, nothing, or only one matching key/value is replaced, * else all matching key/values (regardless how many) are removed, * before the new pair is written. @@ -1966,6 +1976,9 @@ int git_config_set_multivar_in_file(const char *config_filename, } else store.do_not_match = 0; + if (value_regex == CONFIG_REGEX_NONE) + store.value_never_matches = 1; + store.value_regex = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(store.value_regex, value_regex, REG_EXTENDED)) { diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh index e5c0f07..3b92083 100755 --- a/t/t1303-wacky-config.sh +++ b/t/t1303-wacky-config.sh @@ -111,7 +111,7 @@ test_expect_success 'unset many entries' ' test_must_fail git config section.key ' -test_expect_failure '--add appends new value after existing empty value' ' +test_expect_success '--add appends new value after existing empty value' ' cat >expect <<-\EOF && -- 1.9.0.GIT -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html