@@ -626,6 +626,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
char *value;
+ int flags = 0;
given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
@@ -761,6 +762,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
error(_("--literal only applies with 'value_regex'"));
usage_builtin_config();
}
+ if (literal)
+ flags = CONFIG_FLAGS_LITERAL_VALUE;
if (actions & PAGING_ACTIONS)
setup_auto_pager("config", 1);
@@ -823,7 +826,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
value = normalize_value(argv[0], argv[1]);
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2], 0);
+ argv[0], value, argv[2],
+ flags);
}
else if (actions == ACTION_ADD) {
check_write();
@@ -832,7 +836,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value,
- CONFIG_REGEX_NONE, 0);
+ CONFIG_REGEX_NONE,
+ flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
@@ -841,7 +846,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2],
- CONFIG_FLAGS_MULTI_REPLACE);
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -868,7 +873,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 1, 2);
if (argc == 2)
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1], 0);
+ argv[0], NULL, argv[1],
+ flags);
else
return git_config_set_in_file_gently(given_config_source.file,
argv[0], NULL);
@@ -878,7 +884,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 1, 2);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], NULL, argv[1],
- CONFIG_FLAGS_MULTI_REPLACE);
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
@@ -2402,6 +2402,7 @@ struct config_store_data {
size_t baselen;
char *key;
int do_not_match;
+ const char *literal_value;
regex_t *value_regex;
int multi_replace;
struct {
@@ -2431,6 +2432,8 @@ static int matches(const char *key, const char *value,
{
if (strcmp(key, store->key))
return 0; /* not ours */
+ if (store->literal_value)
+ return !strcmp(store->literal_value, value);
if (!store->value_regex)
return 1; /* always matches */
if (store->value_regex == CONFIG_REGEX_NONE)
@@ -2803,6 +2806,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
store.value_regex = NULL;
else if (value_regex == CONFIG_REGEX_NONE)
store.value_regex = CONFIG_REGEX_NONE;
+ else if (flags & CONFIG_FLAGS_LITERAL_VALUE)
+ store.literal_value = value_regex;
else {
if (value_regex[0] == '!') {
store.do_not_match = 1;
@@ -77,6 +77,13 @@ enum config_event_t {
*/
#define CONFIG_FLAGS_MULTI_REPLACE (1 << 0)
+/*
+ * When CONFIG_FLAGS_LITERAL_VALUE is specified, match key/value pairs
+ * by string comparison (not regex match) to the provided value_regex
+ * parameter.
+ */
+#define CONFIG_FLAGS_LITERAL_VALUE (1 << 1)
+
/*
* The parser event function (if not NULL) is called with the event type and
* the begin/end offsets of the parsed elements.
@@ -1978,4 +1978,52 @@ test_expect_success 'refuse --literal-value for incompatible actions' '
test_must_fail git config --literal-value --edit
'
+test_expect_success '--literal-value uses exact string matching' '
+ GLOB="a+b*c?d[e]f.g" &&
+ q_to_tab >initial <<-EOF &&
+ [literal]
+ Qtest = $GLOB
+ EOF
+
+ cp initial .git/config &&
+ git config literal.test bogus "$GLOB" &&
+ q_to_tab >expect <<-EOF &&
+ [literal]
+ Qtest = $GLOB
+ Qtest = bogus
+ EOF
+ test_cmp expect .git/config &&
+ cp initial .git/config &&
+ git config --literal-value literal.test bogus "$GLOB" &&
+ q_to_tab >expect <<-EOF &&
+ [literal]
+ Qtest = bogus
+ EOF
+ test_cmp expect .git/config &&
+
+ cp initial .git/config &&
+ test_must_fail git config --unset literal.test "$GLOB" &&
+ git config --literal-value --unset literal.test "$GLOB" &&
+ test_must_fail git config literal.test &&
+
+ cp initial .git/config &&
+ test_must_fail git config --unset-all literal.test "$GLOB" &&
+ git config --literal-value --unset-all literal.test "$GLOB" &&
+ test_must_fail git config literal.test &&
+
+ cp initial .git/config &&
+ git config --replace-all literal.test bogus "$GLOB" &&
+ q_to_tab >expect <<-EOF &&
+ [literal]
+ Qtest = $GLOB
+ Qtest = bogus
+ EOF
+ test_cmp expect .git/config &&
+
+ cp initial .git/config &&
+ git config --replace-all literal.test bogus "$GLOB" &&
+ git config --literal-value --replace-all literal.test bogus "$GLOB" &&
+ test_cmp_config bogus literal.test
+'
+
test_done