Skip to contentSkip to conversation

config: allow user to know scope of config options

PATCH Superseded Matthew Rogers via GitGitGadget 7 participants 98 messages Dec 18, 2019 – Feb 11, 2020 Documentation

lore
Share & tools
lore
#0 lore raw

cover config: allow user to know scope of config options

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

Matthew Rogers (1):
config: allow user to know scope of config options

 builtin/config.c  | 60 ++++++++++++++++++++++++++++++++++++++++-------
 t/t1300-config.sh | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 8 deletions(-)

base-commit: b02fd2accad4d48078671adf38fe5b5976d77304
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/1 config: allow user to know scope of config options

From: Matthew Rogers <[email protected]>

Add new option --show-scope which allows a user to know what the scope of listed config options are (local/global/system/etc.).

---
 builtin/config.c  | 60 ++++++++++++++++++++++++++++++++++++++++-------
 t/t1300-config.sh | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 8 deletions(-)
builtin/config.c +52 -8
index 98d65bc0ad..9a9c2d12f2 100644
@@ -29,10 +29,11 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -151,10 +152,11 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (system, global, local, command line)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -178,23 +180,63 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
 	strbuf_addch(buf, term);
 }
 
+static const char *scope_to_string(enum config_scope scope) {
+	/*
+	 * --local, --global, and --system work the same as --file so there's
+	 * no easy way for the parser to tell the difference when it is
+	 * setting the scope, so we use our information about which options
+	 * were passed
+	 */
+	if (use_local_config || scope == CONFIG_SCOPE_REPO) {
+		return "local";
+	} else if (use_global_config || scope == CONFIG_SCOPE_GLOBAL) {
+		return "global";
+	} else if (use_system_config || scope == CONFIG_SCOPE_SYSTEM) {
+		return "system";
+	} else if (given_config_source.use_stdin ||
+		given_config_source.blob ||
+		given_config_source.file ||
+		scope == CONFIG_SCOPE_CMDLINE) {
+		return "command line";
+	} else {
+		return "unknown";
+	}
+}
+
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = scope_to_string(current_config_scope());
+
+	strbuf_addch(buf, '(');
+	if (end_nul)
+		strbuf_addstr(buf, N_(scope));
+	else
+		quote_c_style(scope, buf, NULL, 0);
+	strbuf_addch(buf, ')');
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
-		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
+		/* Use fwrite as "buf" can contain \0's if "end_nul" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);
 	}
@@ -213,6 +255,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_scope(buf);
 	if (show_origin)
 		show_config_origin(buf);
 	if (show_keys)
@@ -678,7 +722,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
t/t1300-config.sh +51 -0

57 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#2 lore raw

Review

Quoted 8 lines · Matthew Rogers via GitGitGadget
(quoted diff) +4 -4
-static int end_null;
+static int end_nul;
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
-	if (end_null)
+	if (end_nul)

These are correct changes, but is unrelated noise in the context of the theme of the patch, no?

builtin/config.c static void check_argc(int argc, int min, int max) · line 206

Quoted 13 lines
builtin/config.c +13 -0
+static const char *scope_to_string(enum config_scope scope) {
+	/*
+	 * --local, --global, and --system work the same as --file so there's
+	 * no easy way for the parser to tell the difference when it is
+	 * setting the scope, so we use our information about which options
+	 * were passed
+	 */
+	if (use_local_config || scope == CONFIG_SCOPE_REPO) {
+		return "local";
+	} else if (use_global_config || scope == CONFIG_SCOPE_GLOBAL) {
+		return "global";
+	} else if (use_system_config || scope == CONFIG_SCOPE_SYSTEM) {
+		return "system";

The above is slightly tricky; --global/--system/--local are made mutually exclusive in the higher level, so if any of them is set, we do not even need to look at the "scope" to tell what kind of source we are reading from.

builtin/config.c static void check_argc(int argc, int min, int max) · line 211

Quoted 5 lines
builtin/config.c +5 -0
+	} else if (given_config_source.use_stdin ||
+		given_config_source.blob ||
+		given_config_source.file ||
+		scope == CONFIG_SCOPE_CMDLINE) {
+		return "command line";

I am not sure what the implication of saying "they came from the command line" when we read from the standard input or from a blob.

builtin/config.c static void check_argc(int argc, int min, int max) · line 215

Quoted 4 lines
builtin/config.c +4 -0
+	} else {
+		return "unknown";
+	}
+}

In any case, the need for such logic that says "scope might not say it is REPO, but when use_local_config is true, we are doing a local config" implies that "scope" parameter the caller of this function has is not set correctly when these options are used---would that be the real bug that needs fixing, rather than getting "worked around" with a code like this?

It almost makes me point fingers at config.c::config_with_options() where config_source is inspected and git_config_from_*() helpers are called without setting the current_parsing_scope. Unlike these cases, when do_git_config_sequence() is called from that function, the scope is recorded in the variable before each standard config source file is opened and read. What would we be breaking if we taught the function to set the current_parsing_scope variable correctly even when reading from the config_source? That would certainly simplify this function quite a lot, but if the other parts of the codebase relies on the current behaviour, we cannot make such a change lightly.

builtin/config.c static void check_argc(int argc, int min, int max) · line 226

Quoted 10 lines
builtin/config.c +10 -0
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = scope_to_string(current_config_scope());
+
+	strbuf_addch(buf, '(');
+	if (end_nul)
+		strbuf_addstr(buf, N_(scope));
+	else
+		quote_c_style(scope, buf, NULL, 0);

Isn't this overkill? I think this code was copied-and-pasted from the other function that needs to show an arbitrary end-user supplied data which is a pathname, so it makes perfect sense to use c-style quoting, but the token scope_to_string() returns is taken from a bounded set that doesn't require such quoting, no?

Quoted 4 lines
builtin/config.c +4 -0
+	strbuf_addch(buf, ')');
+	strbuf_addch(buf, term);
+}
+
#5 lore raw
In reply to Matthew Rogers via GitGitGadget

Hi Matthew,

Quoted 10 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Add new option --show-scope which allows a user to know what the scope of listed config options are (local/global/system/etc.).

---
 builtin/config.c  | 60 ++++++++++++++++++++++++++++++++++++++++-------
 t/t1300-config.sh | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 8 deletions(-)

Doesn't this also need a man page update as well for adding the option to the synopsis.

The commit message doesn't fully highlight that the config list will often be all the users config values, so each value will be disambiguated/identified as to it's origin.

Philip

#6 lore raw

Junio,

Quoted 2 lines

These are correct changes, but is unrelated noise in the context of the theme of the patch, no?

I think that's the case, would the recommended course of action be to move these changes into its own commit?

Quoted 11 lines

builtin/config.c static void check_argc(int argc, int min, int max) · line 206

Quoted 6 lines
builtin/config.c +6 -0
+     if (use_local_config || scope == CONFIG_SCOPE_REPO) {
+             return "local";
+     } else if (use_global_config || scope == CONFIG_SCOPE_GLOBAL) {
+             return "global";
+     } else if (use_system_config || scope == CONFIG_SCOPE_SYSTEM) {
+             return "system";

The above is slightly tricky; --global/--system/--local are made mutually exclusive in the higher level, so if any of them is set, we do not even need to look at the "scope" to tell what kind of source we are reading from.

So the way I structured these was to mirror the way other parts of this file check if we should be doing a --local, etc. and mirrored that here. This could definitely be cleaned up if we change the behavior with how --local, etc. set the current_config_scope.

Quoted 8 lines

builtin/config.c static void check_argc(int argc, int min, int max) · line 211

Quoted 5 lines
builtin/config.c +5 -0
+     } else if (given_config_source.use_stdin ||
+             given_config_source.blob ||
+             given_config_source.file ||
+             scope == CONFIG_SCOPE_CMDLINE) {
+             return "command line";

I am not sure what the implication of saying "they came from the command line" when we read from the standard input or from a blob.

I agree with you here, I only put this as "command line" because they came from a place that was ultimately fed in from command line options (--file/--blob). I wouldn't have a problem with calling them out as their own scope ("file", "blob", "stdin").

Quoted 12 lines

builtin/config.c static void check_argc(int argc, int min, int max) · line 215

Quoted 4 lines
builtin/config.c +4 -0
+     } else {
+             return "unknown";
+     }
+}

In any case, the need for such logic that says "scope might not say it is REPO, but when use_local_config is true, we are doing a local config" implies that "scope" parameter the caller of this function has is not set correctly when these options are used---would that be the real bug that needs fixing, rather than getting "worked around" with a code like this?

Quoted 11 lines

It almost makes me point fingers at config.c::config_with_options() where config_source is inspected and git_config_from_*() helpers are called without setting the current_parsing_scope. Unlike these cases, when do_git_config_sequence() is called from that function, the scope is recorded in the variable before each standard config source file is opened and read. What would we be breaking if we taught the function to set the current_parsing_scope variable correctly even when reading from the config_source? That would certainly simplify this function quite a lot, but if the other parts of the codebase relies on the current behaviour, we cannot make such a change lightly.

From what I can tell from a cursory glance. the only two clients of this function are remote.c and upload-pack.c. The usecase for remote.c
mostly seems to be to determine the result of remote_is_configured()
which (more importantly) seems to be done when that iterates through the relevant configuration options. Similarly for upload-pack.c.

I don't think it would be harmful for git config --local, etc. to set that as we would normally intuit.

Quoted 8 lines
Quoted 8 lines
builtin/config.c +8 -0
+static void show_config_scope(struct strbuf *buf)
+{
+     const char term = end_nul ? '\0' : '\t';
+     const char *scope = scope_to_string(current_config_scope());
+
+     strbuf_addch(buf, '(');
+     if (end_nul)
+             strbuf_addstr(buf, N_(scope));
Quoted 8 lines

builtin/config.c static void check_argc(int argc, int min, int max) · line 226

Quoted 2 lines
builtin/config.c +2 -0
+     else
+             quote_c_style(scope, buf, NULL, 0);

Isn't this overkill? I think this code was copied-and-pasted from the other function that needs to show an arbitrary end-user supplied data which is a pathname, so it makes perfect sense to use c-style quoting, but the token scope_to_string() returns is taken from a bounded set that doesn't require such quoting, no?

Yeah, I guess that is a copy+paste mistake. I don't think its necessary since we control the input into this function, So I'll fix that.

Philip,

Quoted 6 lines

Doesn't this also need a man page update as well for adding the option to the synopsis.

The commit message doesn't fully highlight that the config list will often be all the users config values, so each value will be disambiguated/identified as to it's origin.

I'm agreed on these. So I'll look to readjust that.

#3 lore raw
In reply to Junio C Hamano
Quoted 11 lines · Junio C Hamano

It almost makes me point fingers at config.c::config_with_options() where config_source is inspected and git_config_from_*() helpers are called without setting the current_parsing_scope. Unlike these cases, when do_git_config_sequence() is called from that function, the scope is recorded in the variable before each standard config source file is opened and read. What would we be breaking if we taught the function to set the current_parsing_scope variable correctly even when reading from the config_source? That would certainly simplify this function quite a lot, but if the other parts of the codebase relies on the current behaviour, we cannot make such a change lightly.

As the author of the SCOPE enum, I think this is the right direction. The only users of current_config_scope() are in config callbacks (e.g., upload_pack_config() checks it for the "packobjectshook"), which you couldn't trigger via "git config" anyway.

The main reason I didn't set the scope before in config_with_options() is that it's not given the scope at all; git-config resolves it to the filename. So if git_config_source grows an enum to select the type, and all that filename-resolution gets pushed down into config_with_options(), the whole thing would fall out naturally, I think.

-Peff

#4 lore raw
Quoted 3 lines · Jeff King

... So if git_config_source grows an enum to select the type, and all that filename-resolution gets pushed down into config_with_options(), the whole thing would fall out naturally, I think.

Makes sense.

#7 lore raw
In reply to [email protected]
Quoted 6 lines · <[email protected]> writes:
Quoted 2 lines

These are correct changes, but is unrelated noise in the context of the theme of the patch, no?

I think that's the case, would the recommended course of action be to move these changes into its own commit?

Yup, and it generally is a good idea to make such a clean-up patch either early in the series, or as a standalone patch (with a note under three-dash lines that another topic is coming on top of the cleanup), because it would be much less likely to introduce new bugs and can be merged quicly to 'next' and then to 'master' to serve as a base to build your other changes on top.

#8 lore raw

Philip,

Quoted 3 lines

The commit message doesn't fully highlight that the config list will often be all the users config values, so each value will be disambiguated/identified as to it's origin.

I don't really understand what you mean by "it's origin" here. When you say origin, do you mean in the "--show-origin" sense of "file/blob/etc." or something else? Because scope is kind of an orthogonal concept to origin in that sense as you can have files with different origins but the same scope.

Thanks,
Matt

Quoted 17 lines · Junio C Hamano
Quoted 6 lines · <[email protected]> writes:
Quoted 2 lines

These are correct changes, but is unrelated noise in the context of the theme of the patch, no?

I think that's the case, would the recommended course of action be to move these changes into its own commit?

Yup, and it generally is a good idea to make such a clean-up patch either early in the series, or as a standalone patch (with a note under three-dash lines that another topic is coming on top of the cleanup), because it would be much less likely to introduce new bugs and can be merged quicly to 'next' and then to 'master' to serve as a base to build your other changes on top.

Signature · 1 line
Matthew Rogers
#9 lore raw
Quoted 10 lines · Matt Rogers

Philip,

Quoted 3 lines

The commit message doesn't fully highlight that the config list will often be all the users config values, so each value will be disambiguated/identified as to it's origin.

I don't really understand what you mean by "it's origin" here. When you say origin, do you mean in the "--show-origin" sense of "file/blob/etc." or something else? Because scope is kind of an orthogonal concept to origin in that sense as you can have files with different origins but the same scope.

I do not think origin and scope are orghogonal, though. Can the same file appear as the source for different configuration var-value pair in two different scopes?

It is likely that you can _guess_ with high precision that given a pathname reported by --show-origin what scope it is in. It on the other hand is not so trivial given a scope to guess which exact file a var-value pair came from, I would think.\

#10 lore raw
Quoted 4 lines · Junio C Hamano

I do not think origin and scope are orghogonal, though. Can the same file appear as the source for different configuration var-value pair in two different scopes?

I meant orthogonal in two senses:

That given the current implementation you don't need to have both options active at
the same time but can have them active at both times.

And that origin and scope correlate, but aren't necessarily one-for-one. For example, --show-origin lists in a known order, but it follows includes and lists the origin as the included file. so if you include a file globally which has includeif "gitdir:..." directives then it can get hairy when all your config files are structured like that.

Although, to be fair I doubt that that kind of situation is normal

Quoted 5 lines

It is likely that you can _guess_ with high precision that given a pathname reported by --show-origin what scope it is in. It on the other hand is not so trivial given a scope to guess which exact file a var-value pair came from, I would think.\

Normally yes, but things can get complicating depending on your configuration/include situation.

#11 lore raw
Quoted 2 lines · Matt Rogers

And that origin and scope correlate, but aren't necessarily one-for-one.

Yes, exactly. When I see "orthogonal", I expect the word describes things that do not correlate.

I can see values in the option that gives scope but not path in order to write scripts that limits var-value pairs to be used (e.g. "I do not want to be affected by the per-repository values", "I do not trust settings that comes system-wide"). I also can see values in the option that gives only path when debugging the configuration file.

I briefly wondered, for the purpose of such "I do want to see only those settings coming from these scopes" script, it may make more sense to have the command _filter_ the var-value pairs, instead of showing all of them with label, but that feature always exists ;-)

#13 lore raw

PATCH v2 1/4 config: fix typo in variable name

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#17 lore raw

PATCH v2 2/4 config: fix config scope enum

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases.

Additionally we rename what was CONFIG_SCOPE_REPO to CONFIG_SCOPE_LOCAL to reflect its new, more specific meaning.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 upload-pack.c          | 3 ++-
 5 files changed, 11 insertions(+), 9 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#12 lore raw

v2 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v1:

* Cleaned up meaning of scoping, specifically separating "repo" into "local" and "worktree" as well as expanding "cmdline" into "command" scoping, added submodule scoping
* Taught struct git_config_source to remember the scope of the command that is filling it out
* do_git_config_sequence() now remembers the previous scope so that if it is called recursively it can remember where it was.
* Added documentation for this new option

Matthew Rogers (4):
config: fix typo in variable name
config: fix config scope enum
config: clarify meaning of command line scoping
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt | 15 +++++---
 builtin/config.c             | 66 ++++++++++++++++++++++++++++++------
 config.c                     | 15 ++++----
 config.h                     | 19 ++++++-----
 remote.c                     |  3 +-
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       |  8 +++--
 t/t1300-config.sh            | 50 +++++++++++++++++++++++++++
 upload-pack.c                |  3 +-
 9 files changed, 148 insertions(+), 35 deletions(-)

base-commit: 7a6a90c6ec48fc78c83d7090d6c1b95d8f3739c0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v1:

 -:  ---------- > 1:  b40480f03a config: fix typo in variable name
 -:  ---------- > 2:  e8e05f3940 config: fix config scope enum
 -:  ---------- > 3:  8225273546 config: clarify meaning of command line scoping
 1:  ec699bb3e6 ! 4:  92ce9b7824 config: allow user to know scope of config options
     @@ -1,21 +1,62 @@
      Author: Matthew Rogers <[email protected]>
      
     -    config: allow user to know scope of config options
     +    config: add '--show-scope' to print the scope of a config value
      
     -    Add new option --show-scope which allows a user to know what the scope
     -    of listed config options are (local/global/system/etc.).
     +    When a user queries config values with --show-origin, often it's
     +    difficult to determine what the actual "scope" (local, global, etc.) of
     +    a given value is based on just the origin file.
     +
     +    Teach 'git config' the '--show-scope' option to print the scope of all
     +    displayed config values.  Note that we should never see anything of
     +    "submodule" scope as that is only ever used by submodule-config.c when
     +    parsing the '.gitmodules' file.
      
          Signed-off-by: Matthew Rogers <[email protected]>
      
     + diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
     + --- a/Documentation/git-config.txt
     + +++ b/Documentation/git-config.txt
     +@@
     + SYNOPSIS
     + --------
     + [verse]
     +-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
     ++'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
     + 'git config' [<file-option>] [--type=<type>] --add name value
     + 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
     +-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
     +-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
     +-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
     ++'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
     ++'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
     ++'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
     + 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
     + 'git config' [<file-option>] --unset name [value_regex]
     + 'git config' [<file-option>] --unset-all name [value_regex]
     + 'git config' [<file-option>] --rename-section old_name new_name
     + 'git config' [<file-option>] --remove-section name
     +-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
     ++'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
     + 'git config' [<file-option>] --get-color name [default]
     + 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
     + 'git config' [<file-option>] -e | --edit
     +@@
     + 	the actual origin (config file path, ref, or blob id if
     + 	applicable).
     + 
     ++--show-scope::
     ++	Similar to `--show-origin` in that it augments the output of
     ++	all queried config options with the scope of that value 
     ++	(local, global, system, command).
     ++
     + --get-colorbool name [stdout-is-tty]::
     + 
     + 	Find the color setting for `name` (e.g. `color.diff`) and output
     +
       diff --git a/builtin/config.c b/builtin/config.c
       --- a/builtin/config.c
       +++ b/builtin/config.c
      @@
     - static struct git_config_source given_config_source;
     - static int actions, type;
     - static char *default_value;
     --static int end_null;
     -+static int end_nul;
       static int respect_includes_opt = -1;
       static struct config_options config_options;
       static int show_origin;
     @@ -24,69 +65,41 @@
       #define ACTION_GET (1<<0)
       #define ACTION_GET_ALL (1<<1)
      @@
     - 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
     - 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
     - 	OPT_GROUP(N_("Other")),
     --	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
     -+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
       	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
       	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
       	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
     -+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (system, global, local, command line)")),
     ++	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
       	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
       	OPT_END(),
       };
      @@
     - 
     - static void show_config_origin(struct strbuf *buf)
     - {
     --	const char term = end_null ? '\0' : '\t';
     -+	const char term = end_nul ? '\0' : '\t';
     - 
     - 	strbuf_addstr(buf, current_config_origin_type());
     - 	strbuf_addch(buf, ':');
     --	if (end_null)
     -+	if (end_nul)
     - 		strbuf_addstr(buf, current_config_name());
     - 	else
     - 		quote_c_style(current_config_name(), buf, NULL, 0);
       	strbuf_addch(buf, term);
       }
       
      +static const char *scope_to_string(enum config_scope scope) {
     -+	/*
     -+	 * --local, --global, and --system work the same as --file so there's
     -+	 * no easy way for the parser to tell the difference when it is
     -+	 * setting the scope, so we use our information about which options
     -+	 * were passed
     -+	 */
     -+	if (use_local_config || scope == CONFIG_SCOPE_REPO) {
     ++	switch (scope) {
     ++	case CONFIG_SCOPE_LOCAL:
      +		return "local";
     -+	} else if (use_global_config || scope == CONFIG_SCOPE_GLOBAL) {
     ++	case CONFIG_SCOPE_GLOBAL:
      +		return "global";
     -+	} else if (use_system_config || scope == CONFIG_SCOPE_SYSTEM) {
     ++	case CONFIG_SCOPE_SYSTEM:
      +		return "system";
     -+	} else if (given_config_source.use_stdin ||
     -+		given_config_source.blob ||
     -+		given_config_source.file ||
     -+		scope == CONFIG_SCOPE_CMDLINE) {
     -+		return "command line";
     -+	} else {
     ++	case CONFIG_SCOPE_WORKTREE:
     ++		return "worktree";
     ++	case CONFIG_SCOPE_COMMAND:
     ++		return "command";
     ++	case CONFIG_SCOPE_SUBMODULE:
     ++		return "submodule";
     ++	default:
      +		return "unknown";
      +	}
      +}
      +
     -+static void show_config_scope(struct strbuf *buf)
     -+{
     ++static void show_config_scope(struct strbuf *buf) {
      +	const char term = end_nul ? '\0' : '\t';
      +	const char *scope = scope_to_string(current_config_scope());
      +
     -+	strbuf_addch(buf, '(');
     -+	if (end_nul)
     -+		strbuf_addstr(buf, N_(scope));
     -+	else
     -+		quote_c_style(scope, buf, NULL, 0);
     -+	strbuf_addch(buf, ')');
     ++	strbuf_addstr(buf, N_(scope));
      +	strbuf_addch(buf, term);
      +}
      +
     @@ -96,33 +109,188 @@
      +	if (show_origin || show_scope) {
       		struct strbuf buf = STRBUF_INIT;
      -		show_config_origin(&buf);
     --		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
      +		if (show_scope)
      +			show_config_scope(&buf);
      +		if (show_origin)
      +			show_config_origin(&buf);
     -+		/* Use fwrite as "buf" can contain \0's if "end_nul" is set. */
     + 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
       		fwrite(buf.buf, 1, buf.len, stdout);
       		strbuf_release(&buf);
     - 	}
      @@
       
       static int format_config(struct strbuf *buf, const char *key_, const char *value_)
       {
      +	if (show_scope)
     -+		show_config_scope(buf);
     ++		show_config_origin(buf);
       	if (show_origin)
       		show_config_origin(buf);
       	if (show_keys)
      @@
     - 		config_options.git_dir = get_git_dir();
     + 	int nongit = !startup_info->have_repository;
     + 	char *value;
     + 
     ++
     ++
     + 	given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
     + 
     + 	argc = parse_options(argc, argv, prefix, builtin_config_options,
     +@@
     + 			!strcmp(given_config_source.file, "-")) {
     + 		given_config_source.file = NULL;
     + 		given_config_source.use_stdin = 1;
     ++		given_config_source.scope = CONFIG_SCOPE_COMMAND;
     + 	}
     + 
     + 	if (use_global_config) {
     +@@
     + 			 */
     + 			die(_("$HOME not set"));
     + 
     ++		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
     ++
     + 		if (access_or_warn(user_config, R_OK, 0) &&
     + 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
     + 			given_config_source.file = xdg_config;
     +@@
     + 			free(xdg_config);
     + 		}
     + 	}
     +-	else if (use_system_config)
     ++	else if (use_system_config) {
     + 		given_config_source.file = git_etc_gitconfig();
     +-	else if (use_local_config)
     ++		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
     ++	} else if (use_local_config) {
     + 		given_config_source.file = git_pathdup("config");
     +-	else if (use_worktree_config) {
     ++		given_config_source.scope = CONFIG_SCOPE_LOCAL;
     ++	} else if (use_worktree_config) {
     + 		struct worktree **worktrees = get_worktrees(0);
     + 		if (repository_format_worktree_config)
     + 			given_config_source.file = git_pathdup("config.worktree");
     +@@
     + 			      "section in \"git help worktree\" for details"));
     + 		else
     + 			given_config_source.file = git_pathdup("config");
     ++		given_config_source.scope = CONFIG_SCOPE_LOCAL;
     + 		free_worktrees(worktrees);
     + 	} else if (given_config_source.file) {
     + 		if (!is_absolute_path(given_config_source.file) && prefix)
     + 			given_config_source.file =
     + 				prefix_filename(prefix, given_config_source.file);
     ++		given_config_source.scope = CONFIG_SCOPE_COMMAND;
     ++	} else if (given_config_source.blob) {
     ++		given_config_source.scope = CONFIG_SCOPE_COMMAND;
     + 	}
     + 
     ++
     + 	if (respect_includes_opt == -1)
     + 		config_options.respect_includes = !given_config_source.file;
     + 	else
     +
     + diff --git a/config.c b/config.c
     + --- a/config.c
     + +++ b/config.c
     +@@
     + 	char *xdg_config = xdg_config_home("config");
     + 	char *user_config = expand_user_path("~/.gitconfig", 0);
     + 	char *repo_config;
     ++	enum config_scope prev_parsing_scope = current_parsing_scope;
     + 
     + 	if (opts->commondir)
     + 		repo_config = mkpathdup("%s/config", opts->commondir);
     +@@
     + 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
     + 		die(_("unable to parse command-line config"));
     + 
     +-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
     ++	current_parsing_scope = prev_parsing_scope;
     + 	free(xdg_config);
     + 	free(user_config);
     + 	free(repo_config);
     +@@
     + 		data = &inc;
       	}
       
     --	if (end_null) {
     -+	if (end_nul) {
     - 		term = '\0';
     - 		delim = '\n';
     - 		key_delim = '\n';
     ++	if (config_source)
     ++		current_parsing_scope = config_source->scope;
     ++
     + 	/*
     + 	 * If we have a specific filename, use it. Otherwise, follow the
     + 	 * regular lookup sequence.
     +
     + diff --git a/config.h b/config.h
     + --- a/config.h
     + +++ b/config.h
     +@@
     + 
     + #define CONFIG_REGEX_NONE ((void *)1)
     + 
     ++enum config_scope {
     ++	CONFIG_SCOPE_UNKNOWN = 0,
     ++	CONFIG_SCOPE_SYSTEM,
     ++	CONFIG_SCOPE_GLOBAL,
     ++	CONFIG_SCOPE_LOCAL,
     ++	CONFIG_SCOPE_WORKTREE,
     ++	CONFIG_SCOPE_COMMAND,
     ++	CONFIG_SCOPE_SUBMODULE,
     ++};
     ++
     + struct git_config_source {
     + 	unsigned int use_stdin:1;
     + 	const char *file;
     + 	const char *blob;
     ++	enum config_scope scope;
     + };
     + 
     + enum config_origin_type {
     +@@
     + 
     + int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
     + 
     +-enum config_scope {
     +-	CONFIG_SCOPE_UNKNOWN = 0,
     +-	CONFIG_SCOPE_SYSTEM,
     +-	CONFIG_SCOPE_GLOBAL,
     +-	CONFIG_SCOPE_LOCAL,
     +-	CONFIG_SCOPE_WORKTREE,
     +-	CONFIG_SCOPE_COMMAND,
     +-};
     +-
     + enum config_scope current_config_scope(void);
     + const char *current_config_origin_type(void);
     + const char *current_config_name(void);
     +
     + diff --git a/submodule-config.c b/submodule-config.c
     + --- a/submodule-config.c
     + +++ b/submodule-config.c
     +@@
     + static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
     + {
     + 	if (repo->worktree) {
     +-		struct git_config_source config_source = { 0 };
     ++		struct git_config_source config_source = {
     ++			0, .scope = CONFIG_SCOPE_SUBMODULE
     ++		};
     + 		const struct config_options opts = { 0 };
     + 		struct object_id oid;
     + 		char *file;
     +
     + diff --git a/t/helper/test-config.c b/t/helper/test-config.c
     + --- a/t/helper/test-config.c
     + +++ b/t/helper/test-config.c
     +@@
     + 		return "repo";
     + 	case CONFIG_SCOPE_WORKTREE:
     + 		return "worktree";
     ++	case CONFIG_SCOPE_SUBMODULE:
     ++		return "submodule";
     + 	case CONFIG_SCOPE_COMMAND:
     +-		return "command";
     ++		return "cmdline";
     + 	default:
     + 		return "unknown";
     + 	}
      
       diff --git a/t/t1300-config.sh b/t/t1300-config.sh
       --- a/t/t1300-config.sh
     @@ -131,18 +299,17 @@
       	test_cmp expect output
       '
       
     -+
      +test_expect_success '--show-scope with --list' '
      +	cat >expect <<-EOF &&
     -+		(global)	user.global=true
     -+		(global)	user.override=global
     -+		(global)	include.path=$INCLUDE_DIR/absolute.include
     -+		(global)	user.absolute=include
     -+		(local)	user.local=true
     -+		(local)	user.override=local
     -+		(local)	include.path=../include/relative.include
     -+		(local)	user.relative=include
     -+		(command line)	user.cmdline=true
     ++		global	user.global=true
     ++		global	user.override=global
     ++		global	include.path=$INCLUDE_DIR/absolute.include
     ++		global	user.absolute=include
     ++		local	user.local=true
     ++		local	user.override=local
     ++		local	include.path=../include/relative.include
     ++		local	user.relative=include
     ++		command	user.cmdline=true
      +	EOF
      +	git -c user.cmdline=true config --list --show-scope >output &&
      +	test_cmp expect output
     @@ -151,16 +318,16 @@
      +test_expect_success !MINGW '--show-scope with --blob' '
      +	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
      +	cat >expect <<-EOF &&
     -+		(command line)	user.custom=true
     ++		command	user.custom=true
      +	EOF
      +	git config --blob=$blob --show-scope --list >output &&
      +	test_cmp expect output
      +'
      +test_expect_success '--show-scope with --local' '
      +	cat >expect <<-\EOF &&
     -+		(local)	user.local=true
     -+		(local)	user.override=local
     -+		(local)	include.path=../include/relative.include
     ++		local	user.local=true
     ++		local	user.override=local
     ++		local	include.path=../include/relative.include
      +	EOF
      +	git config --local --list --show-scope >output &&
      +	test_cmp expect output
     @@ -168,15 +335,15 @@
      +
      +test_expect_success '--show-scope with --show-origin' '
      +	cat >expect <<-EOF &&
     -+		(global)	file:$HOME/.gitconfig	user.global=true
     -+		(global)	file:$HOME/.gitconfig	user.override=global
     -+		(global)	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
     -+		(global)	file:$INCLUDE_DIR/absolute.include	user.absolute=include
     -+		(local)	file:.git/config	user.local=true
     -+		(local)	file:.git/config	user.override=local
     -+		(local)	file:.git/config	include.path=../include/relative.include
     -+		(local)	file:.git/../include/relative.include	user.relative=include
     -+		(command line)	command line:	user.cmdline=true
     ++		global	file:$HOME/.gitconfig	user.global=true
     ++		global	file:$HOME/.gitconfig	user.override=global
     ++		global	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
     ++		global	file:$INCLUDE_DIR/absolute.include	user.absolute=include
     ++		local	file:.git/config	user.local=true
     ++		local	file:.git/config	user.override=local
     ++		local	file:.git/config	include.path=../include/relative.include
     ++		local	file:.git/../include/relative.include	user.relative=include
     ++		command	command line:	user.cmdline=true
      +	EOF
      +	git -c user.cmdline=true config --list --show-origin --show-scope >output &&
      +	test_cmp expect output
Signature · 1 line
gitgitgadget
#20 lore raw

PATCH v2 3/4 config: clarify meaning of command line scoping

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. This is a little bit too specific as there are other methods to pass config values so that the last for a single command (namely --file and --blob). As the "visibility" of config values passed by these situations is common, we unify them as having a scope of "command" rather than "command line".

---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 6695e463eb..78bbb9eb98 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
Signature · 1 line
gitgitgadget
#23 lore raw

PATCH v2 4/4 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++----
 builtin/config.c             | 56 ++++++++++++++++++++++++++++++++----
 config.c                     |  6 +++-
 config.h                     | 20 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       |  4 ++-
 t/t1300-config.sh            | 50 ++++++++++++++++++++++++++++++++
 7 files changed, 133 insertions(+), 22 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +51 -5

122 lines not on this page · raw message

config.c +5 -1
index f319a3d6a0..035fc8fb29 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
config.h +11 -9
index f383a71404..91f851e925 100644
@@ -35,10 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +305,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +3 -1
index 78bbb9eb98..aae2c6fc9e 100644
@@ -48,8 +48,10 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
 	case CONFIG_SCOPE_COMMAND:
-		return "command";
+		return "cmdline";
 	default:
 		return "unknown";
 	}
t/t1300-config.sh +50 -0

56 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#18 lore raw

Re: [PATCH v2 2/4] config: fix config scope enum

In reply to Matthew Rogers via GitGitGadget
Quoted 6 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases.

Hmph, then "fix" on the title is a bit misleading, no?

The enum may not have been as fine grained as you would have liked, but if there was nothing broken, then we are doing this not to "fix" anything.

A more important thing to explain would probably be why we (i.e. those who propose this change, those who give favoriable reviews to it, and those who accept it change to the system) would want to see finer-grained classification. What do we expect to be able to do with the resulting finer-grained set that we wouldn't be able to with the original, and why is it a good thing? That is what readers of the proposed log message of this change would want to see, I would think.

Quoted 96 lines

Additionally we rename what was CONFIG_SCOPE_REPO to CONFIG_SCOPE_LOCAL to reflect its new, more specific meaning.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 upload-pack.c          | 3 ++-
 5 files changed, 11 insertions(+), 9 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
#14 lore raw

Re: [PATCH v2 1/4] config: fix typo in variable name

In reply to Matthew Rogers via GitGitGadget
Quoted 11 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

Obviously correct.

Malapropism is a new word in "git log" output in our history ;-)

Quoted 45 lines
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
#21 lore raw

Re: [PATCH v2 3/4] config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget
Quoted 6 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. This is a little bit too specific as there are other methods to pass config values so that the last for a single command (namely --file and --blob).

Sorry, but I cannot parse this, especially around "so that the last for ..." part.

Quoted 3 lines

As the "visibility" of config
values passed by these situations is common, we unify them as having a scope of "command" rather than "command line".

Is the "unification" something done by this patch? It does not appear to be so. The existing code already was using CMDLINE to call "git -c VAR=VAL" and also something else (which is not clear to me, unfortunately, probably because I failed to parse the above X-<), and this step renames CMDLINE to COMMAND perhaps because CMDLINE has too strong connotation with the "-c" thing and much less with the other thing (which is not clear to me, unfortunately) and you found that renaming it to COMMAND would cover both cases better?

I also do not get what you meant by "visibility", but it probably is primarily because it is not clear what "the other thing" is.

Quoted 48 lines
---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 6695e463eb..78bbb9eb98 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
#24 lore raw

Re: [PATCH v2 4/4] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget
Quoted 83 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++----
 builtin/config.c             | 56 ++++++++++++++++++++++++++++++++----
 config.c                     |  6 +++-
 config.h                     | 20 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       |  4 ++-
 t/t1300-config.sh            | 50 ++++++++++++++++++++++++++++++++
 7 files changed, 133 insertions(+), 22 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +2 -0
index 52a904cfb1..0367d28ec1 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };

builtin/config.c static void show_config_origin(struct strbuf *buf) · line 194

Quoted 4 lines
builtin/config.c +1 -0
@@ -189,11 +191,41 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static const char *scope_to_string(enum config_scope scope) {

Style: the outermost opening and closing parentheses of a functiond definition sit on their own lines by themselves. Same for the next one.

Quoted 5 lines
builtin/config.c +5 -0
+	switch (scope) {
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";

builtin/config.c static void show_config_origin(struct strbuf *buf) · line 209

Quoted 10 lines
builtin/config.c +10 -0
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";

Makes me wonder if this wants to be done via a table, which would later allow a parser to map in the other direction, taking a string and returning the corresponding enum, more easily (imagine a yet to be invented feature to "list config settings for only this scope").

Quoted 25 lines
builtin/config.c +16 -2
+	}
+}
+
+static void show_config_scope(struct strbuf *buf) {
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = scope_to_string(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);

builtin/config.c struct strbuf_list { · line 251

Quoted 7 lines
builtin/config.c +2 -0
@@ -213,6 +245,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_origin(buf);
 	if (show_origin)
 		show_config_origin(buf);

Shouldn't one of these show scope instead of origin? I wonder how the tests I see later in the patch could have passed with this.

builtin/config.c int cmd_config(int argc, const char **argv, const char *prefix) · line 637

Quoted 7 lines
builtin/config.c +2 -0
 	if (show_keys)
@@ -599,6 +633,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	int nongit = !startup_info->have_repository;
 	char *value;
 
+
+

Unnecessary edit?

Quoted 40 lines
builtin/config.c +8 -3
 	given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
 
 	argc = parse_options(argc, argv, prefix, builtin_config_options,
@@ -622,6 +658,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
 		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
 	if (use_global_config) {
@@ -637,6 +674,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			 */
 			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
 		if (access_or_warn(user_config, R_OK, 0) &&
 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
 			given_config_source.file = xdg_config;
@@ -646,11 +685,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			free(xdg_config);
 		}
 	}
-	else if (use_system_config)
+	else if (use_system_config) {
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
 		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
 		struct worktree **worktrees = get_worktrees(0);
 		if (repository_format_worktree_config)
 			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +703,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			      "section in \"git help worktree\" for details"));
 		else

builtin/config.c int cmd_config(int argc, const char **argv, const char *prefix) · line 714

Quoted 10 lines
builtin/config.c +4 -0
 			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;

These that set scope for individual sources, not just during the normal sequence, are new in this round, and I think it is an improvement.

Quoted 99 lines
builtin/config.c +1 -0
 	}
 
+
 	if (respect_includes_opt == -1)
 		config_options.respect_includes = !given_config_source.file;
 	else
config.c +5 -1
index f319a3d6a0..035fc8fb29 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
config.h +11 -9
index f383a71404..91f851e925 100644
@@ -35,10 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +305,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +0 -0
index 78bbb9eb98..aae2c6fc9e 100644

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 54

Quoted 8 lines
t/helper/test-config.c +3 -1
@@ -48,8 +48,10 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
 	case CONFIG_SCOPE_COMMAND:
-		return "command";
+		return "cmdline";

Oh???

Quoted 64 lines
t/helper/test-config.c +0 -0
 	default:
 		return "unknown";
 	}
t/t1300-config.sh +50 -0
index 983a0a1583..6cecc80b18 100755
@@ -1766,6 +1766,56 @@ test_expect_success !MINGW '--show-origin blob ref' '
 	test_cmp expect output
 '
 
+test_expect_success '--show-scope with --list' '
+	cat >expect <<-EOF &&
+		global	user.global=true
+		global	user.override=global
+		global	include.path=$INCLUDE_DIR/absolute.include
+		global	user.absolute=include
+		local	user.local=true
+		local	user.override=local
+		local	include.path=../include/relative.include
+		local	user.relative=include
+		command	user.cmdline=true
+	EOF
+	git -c user.cmdline=true config --list --show-scope >output &&
+	test_cmp expect output
+'
+
+test_expect_success !MINGW '--show-scope with --blob' '
+	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
+	cat >expect <<-EOF &&
+		command	user.custom=true
+	EOF
+	git config --blob=$blob --show-scope --list >output &&
+	test_cmp expect output
+'
+test_expect_success '--show-scope with --local' '
+	cat >expect <<-\EOF &&
+		local	user.local=true
+		local	user.override=local
+		local	include.path=../include/relative.include
+	EOF
+	git config --local --list --show-scope >output &&
+	test_cmp expect output
+'
+
+test_expect_success '--show-scope with --show-origin' '
+	cat >expect <<-EOF &&
+		global	file:$HOME/.gitconfig	user.global=true
+		global	file:$HOME/.gitconfig	user.override=global
+		global	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+		global	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+		local	file:.git/config	user.local=true
+		local	file:.git/config	user.override=local
+		local	file:.git/config	include.path=../include/relative.include
+		local	file:.git/../include/relative.include	user.relative=include
+		command	command line:	user.cmdline=true
+	EOF
+	git -c user.cmdline=true config --list --show-origin --show-scope >output &&
+	test_cmp expect output
+'
+
 test_expect_success '--local requires a repo' '
 	# we expect 128 to ensure that we do not simply
 	# fail to find anything and return code "1"
#15 lore raw

Re: [PATCH v2 1/4] config: fix typo in variable name

In reply to Junio C Hamano
Quoted 3 lines

Malapropism is a new word in "git log" output in our history ;-)

Yeah, I remember my coworker saying that to me the day I wrote the message and it was just stuck in my head

#19 lore raw

Re: [PATCH v2 2/4] config: fix config scope enum

In reply to Junio C Hamano
Quoted 10 lines · Junio C Hamano
Quoted 6 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases.

Quoted 6 lines

Hmph, then "fix" on the title is a bit misleading, no?

The enum may not have been as fine grained as you would have liked, but if there was nothing broken, then we are doing this not to "fix" anything.

I see where you're coming from, but I would definitely consider this a "fix" in that it's something that (as explained in the deleted comment) should have been this way from the start but was unnecessary as no one had a need for it yet. But I definitely wouldn't be against changing the phrasing to something like "clean up" or whatever your preferred wording would be.

Quoted 9 lines

A more important thing to explain would probably be why we (i.e. those who propose this change, those who give favoriable reviews to it, and those who accept it change to the system) would want to see finer-grained classification. What do we expect to be able to do with the resulting finer-grained set that we wouldn't be able to with the original, and why is it a good thing? That is what readers of the proposed log message of this change would want to see, I would think.

This is really more prep for patch 4 later on in this series, as a user who ran the proposed '--show-scope' later on in the series would care what was "worktree" vs "local".

Regardless, I think the two options I have would be to amend the commit message with that extra information or roll it together with patch 4

#22 lore raw

Re: [PATCH v2 3/4] config: clarify meaning of command line scoping

In reply to Junio C Hamano
Quoted 5 lines · Junio C Hamano
Quoted 2 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Quoted 8 lines
Quoted 4 lines

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. This is a little bit too specific as there are other methods to pass config values so that the last for a single command (namely --file and --blob).

Sorry, but I cannot parse this, especially around "so that the last for ..." part.

My bad, I guess I must have not read as carefully as I thought I did. It should read:
"... there are other methods to pass config values so that _they_ last for a single command ..."

Quoted 4 lines
Quoted 3 lines

As the "visibility" of config
values passed by these situations is common, we unify them as having a scope of "command" rather than "command line".

Quoted 8 lines

Is the "unification" something done by this patch? It does not appear to be so. The existing code already was using CMDLINE to call "git -c VAR=VAL" and also something else (which is not clear to me, unfortunately, probably because I failed to parse the above X-<), and this step renames CMDLINE to COMMAND perhaps because CMDLINE has too strong connotation with the "-c" thing and much less with the other thing (which is not clear to me, unfortunately) and you found that renaming it to COMMAND would cover both cases better?

Essentially, the "unification" was referring to more the unification of all the things that affect configuration only for the duration of a specific command.

The gist of this patch was to say "There are a few ways besides -c to pass a configuration option that lasts for a single command, so it makes sense to broaden that scope.". The change is definitely justified in that COMMAND communicates that much clearer than CMDLINE as REPO, GLOBAL, SYSTEM all describe the thing that can see the configuration options, and it's specifically the
command the can see the -c options and not the command line as a whole.

Quoted 3 lines

I also do not get what you meant by "visibility", but it probably is primarily because it is not clear what "the other thing" is.

I was using visibility as another way to conceptualize scoping. A scope more or less determines who can "see" a thing, so maybe that language was a little bit too much in my head.

The issue is that currently the code doesn't care about any of that (as only -c options actually have COMMAND scoping), so maybe I should roll it into the next patch of the series? As that introduces code that actually cares about the difference?

#25 lore raw

Re: [PATCH v2 4/4] config: add '--show-scope' to print the scope of a config value

In reply to Junio C Hamano
Quoted 16 lines
Quoted 5 lines
builtin/config.c +5 -0
+     switch (scope) {
+     case CONFIG_SCOPE_LOCAL:
+             return "local";
+     case CONFIG_SCOPE_GLOBAL:
+             return "global";

builtin/config.c static void show_config_origin(struct strbuf *buf) · line 209

Quoted 10 lines
builtin/config.c +10 -0
+     case CONFIG_SCOPE_SYSTEM:
+             return "system";
+     case CONFIG_SCOPE_WORKTREE:
+             return "worktree";
+     case CONFIG_SCOPE_COMMAND:
+             return "command";
+     case CONFIG_SCOPE_SUBMODULE:
+             return "submodule";
+     default:
+             return "unknown";
Quoted 4 lines

Makes me wonder if this wants to be done via a table, which would later allow a parser to map in the other direction, taking a string and returning the corresponding enum, more easily (imagine a yet to be invented feature to "list config settings for only this scope").

I was thinking the same but then I realized such an option already exists, --local and company.

Quoted 27 lines
Quoted 27 lines
builtin/config.c +16 -2
+     }
+}
+
+static void show_config_scope(struct strbuf *buf) {
+     const char term = end_nul ? '\0' : '\t';
+     const char *scope = scope_to_string(current_config_scope());
+
+     strbuf_addstr(buf, N_(scope));
+     strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-     if (show_origin) {
+     if (show_origin || show_scope) {
              struct strbuf buf = STRBUF_INIT;
-             show_config_origin(&buf);
+             if (show_scope)
+                     show_config_scope(&buf);
+             if (show_origin)
+                     show_config_origin(&buf);
              /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
              fwrite(buf.buf, 1, buf.len, stdout);
              strbuf_release(&buf);
@@ -213,6 +245,8 @@ struct strbuf_list {
 
Quoted 10 lines

builtin/config.c struct strbuf_list { · line 251

Quoted 6 lines
builtin/config.c +2 -0
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+     if (show_scope)
+             show_config_origin(buf);
      if (show_origin)
              show_config_origin(buf);

Shouldn't one of these show scope instead of origin? I wonder how the tests I see later in the patch could have passed with this.

Oof, that was a blunder... I think this passes the tests because none of them actually hits format_config() only show_all_config() so I'll definitely add a test case for this. (and fix it while I'm at it)

Quoted 7 lines
Quoted 7 lines
t/helper/test-config.c +0 -0
index 78bbb9eb98..aae2c6fc9e 100644
@@ -48,8 +48,10 @@ static const char *scope_name(enum config_scope scope)
              return "repo";
      case CONFIG_SCOPE_WORKTREE:
Quoted 9 lines

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 54

Quoted 6 lines
t/helper/test-config.c +3 -1
              return "worktree";
+     case CONFIG_SCOPE_SUBMODULE:
+             return "submodule";
      case CONFIG_SCOPE_COMMAND:
-             return "command";
+             return "cmdline";

Oh???

I definitely got a little too excited to get this patch in, so I definitely apologize for that,
but thanks for the review.

Signature · 1 line
Matthew Rogers
#16 lore raw

Re: [PATCH v2 1/4] config: fix typo in variable name

In reply to Matthew Rogers via GitGitGadget

builtin/config.c static struct option builtin_config_options[] = { · line 154

Quoted 2 lines · Matthew Rogers via GitGitGadget
builtin/config.c +1 -1
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),

The user-facing option is still spelled "null". Obviously we can't just change that, but if we are trying to prefer "nul", should we offer both?

I think we actually _do_ allow "--nul" because of parse-option's willingness to accept a partial name. But if we wanted to advertise one over the other in "-h", then we'd have to set up the alias ourselves.

Interestingly, "xargs" (and GNU grep) spells it as "--null", so perhaps that's an argument to keep it as-is. Likewise if we accept that "null termination" is a correct name, I suppose.

-Peff

#26 lore raw

v3 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v2:

* Redid commit messages for content/clarity
* Minor fixes around using --show-scope with a single value (format_config)

Matthew Rogers (4):
config: fix typo in variable name
config: refine config scope enum
config: clarify meaning of command line scoping
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt | 15 +++++---
 builtin/config.c             | 66 ++++++++++++++++++++++++++++++------
 config.c                     | 15 ++++----
 config.h                     | 19 ++++++-----
 remote.c                     |  3 +-
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       | 10 ++++--
 t/t1300-config.sh            | 58 +++++++++++++++++++++++++++++++
 t/t1308-config-set.sh        |  2 +-
 upload-pack.c                |  3 +-
 10 files changed, 158 insertions(+), 37 deletions(-)

base-commit: 232378479ee6c66206d47a9be175e3a39682aea6
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v2:

 1:  b40480f03a = 1:  f5a81a4d25 config: fix typo in variable name
 2:  e8e05f3940 ! 2:  f06f9291b7 config: fix config scope enum

@@ -1,14 +1,21 @@
Author: Matthew Rogers <[email protected]>

- config: fix config scope enum
+ config: refine config scope enum

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the
- two cases.
+ two cases, but future functionality may care whether or not the config
+ options come from a worktree or from the repository's actual local
+ config file. For example, the planned feature to add a '--show-scope'
+ to config to allow a user to see which scope listed config options come
+ from would confuse users if it just printed 'repo' rather than 'local'
+ or 'worktree' as the documentation would lead them to expect. As well
+ as the additional benefit of making the implementation look more like
+ how the documentation describes the interface.

- Additionally we rename what was CONFIG_SCOPE_REPO to CONFIG_SCOPE_LOCAL
- to reflect its new, more specific meaning.
+ To accomplish this we split out what was previously considered repo
+ scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about
@@ -82,6 +89,19 @@
return "cmdline";
default:

+ diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
+ --- a/t/t1308-config-set.sh
+ +++ b/t/t1308-config-set.sh
+@@
+ value=from-cmdline
+ origin=command line
+ name=
+- scope=cmdline
++ scope=command
+ EOF
+ GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
+ test_cmp expect actual
+
diff --git a/upload-pack.c b/upload-pack.c
--- a/upload-pack.c
+++ b/upload-pack.c
3: 8225273546 ! 3: 97b8a7641d config: clarify meaning of command line scoping
@@ -3,11 +3,13 @@
config: clarify meaning of command line scoping

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config
- values passed in via the -c option. This is a little bit too specific
- as there are other methods to pass config values so that the last for a
- single command (namely --file and --blob). As the "visibility" of config
- values passed by these situations is common, we unify them as having a
- scope of "command" rather than "command line".
+ values passed in via the -c option. Options passed in using this
+ mechanism share similar scoping characteristics with the --file and
+ --blob options of the 'config' command, namely that they are only in use
+ for that single invocation of git, and that they supersede the normal
+ system/global/local hierarchy. This patch introduces
+ CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes
+ CONFIG_SCOPE_CMDLINE redundant.

4: 92ce9b7824 ! 4: 61ff3c64b5 config: add '--show-scope' to print the scope of a config value

     @@ -76,7 +76,8 @@
       	strbuf_addch(buf, term);
       }
       
     -+static const char *scope_to_string(enum config_scope scope) {
     ++static const char *scope_to_string(enum config_scope scope)
     ++{
      +	switch (scope) {
      +	case CONFIG_SCOPE_LOCAL:
      +		return "local";
     @@ -95,7 +96,8 @@
      +	}
      +}
      +
     -+static void show_config_scope(struct strbuf *buf) {
     ++static void show_config_scope(struct strbuf *buf)
     ++{
      +	const char term = end_nul ? '\0' : '\t';
      +	const char *scope = scope_to_string(current_config_scope());
      +
     @@ -121,19 +123,10 @@
       static int format_config(struct strbuf *buf, const char *key_, const char *value_)
       {
      +	if (show_scope)
     -+		show_config_origin(buf);
     ++		show_config_scope(buf);
       	if (show_origin)
       		show_config_origin(buf);
       	if (show_keys)
     -@@
     - 	int nongit = !startup_info->have_repository;
     - 	char *value;
     - 
     -+
     -+
     - 	given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
     - 
     - 	argc = parse_options(argc, argv, prefix, builtin_config_options,
      @@
       			!strcmp(given_config_source.file, "-")) {
       		given_config_source.file = NULL;
     @@ -286,11 +279,8 @@
      +	case CONFIG_SCOPE_SUBMODULE:
      +		return "submodule";
       	case CONFIG_SCOPE_COMMAND:
     --		return "command";
     -+		return "cmdline";
     + 		return "command";
       	default:
     - 		return "unknown";
     - 	}
      
       diff --git a/t/t1300-config.sh b/t/t1300-config.sh
       --- a/t/t1300-config.sh
     @@ -333,6 +323,14 @@
      +	test_cmp expect output
      +'
      +
     ++test_expect_success '--show-scope getting a single value' '
     ++	cat >expect <<-\EOF &&
     ++		local	true
     ++	EOF
     ++	git config --show-scope --get user.local >output &&
     ++	test_cmp expect output
     ++'
     ++
      +test_expect_success '--show-scope with --show-origin' '
      +	cat >expect <<-EOF &&
      +		global	file:$HOME/.gitconfig	user.global=true
Signature · 1 line
gitgitgadget
#27 lore raw

PATCH v3 1/4 config: fix typo in variable name

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#32 lore raw

PATCH v3 3/4 config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 6695e463eb..78bbb9eb98 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
Signature · 1 line
gitgitgadget
#35 lore raw

PATCH v3 4/4 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++----
 builtin/config.c             | 56 ++++++++++++++++++++++++++++++----
 config.c                     |  6 +++-
 config.h                     | 20 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       |  2 ++
 t/t1300-config.sh            | 58 ++++++++++++++++++++++++++++++++++++
 7 files changed, 140 insertions(+), 21 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +51 -5

116 lines not on this page · raw message

config.c +5 -1
index f319a3d6a0..035fc8fb29 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
config.h +11 -9
index f383a71404..91f851e925 100644
@@ -35,10 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +305,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +2 -0
index 78bbb9eb98..c93bee15c3 100644
@@ -48,6 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
 	case CONFIG_SCOPE_COMMAND:
 		return "command";
 	default:
t/t1300-config.sh +58 -0

64 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#28 lore raw

PATCH v3 2/4 config: refine config scope enum

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 t/t1308-config-set.sh  | 2 +-
 upload-pack.c          | 3 ++-
 6 files changed, 12 insertions(+), 10 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..535b2a73f7 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#29 lore raw

Re: [PATCH v3 2/4] config: refine config scope enum

config.h enum config_scope { · line 304

Quoted 13 lines · Matthew Rogers via GitGitGadget
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };

So the gist of the change is to split REPO into two, LOCAL and WORKTREE.

If we can find a way to state that concisely, perhaps we can improve "refine enum" and make it more informative.

Quoted 21 lines
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +0 -0
index 7b4e1a63eb..535b2a73f7 100755

t/t1308-config-set.sh test_expect_success 'iteration shows correct origins' ' · line 268

Quoted 5 lines
t/t1308-config-set.sh +1 -1
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command

Why???

Quoted 17 lines
t/t1308-config-set.sh +0 -0
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
#33 lore raw

Re: [PATCH v3 3/4] config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget
Quoted 8 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy.

All of the above justifies why it makes sense to treat --file, --blob and "git -c VAR=VAL" as the same scope (i.e. it would have been a nice part of log message of the commit that introduced SCOPE_CMDLINE), but that is not something we need to justify now---we have such a scope for one-shot settings and these three sources are already treated as the same class.

Quoted 3 lines

This patch introduces
CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

The change in this commit is to rename CMDLINE to COMMAND. That is what the proposed log message for this step must justify.

We internally use CONFIG_SCOPE_CMDLINE for the scope for the configuration variables that come from "git -c VAR=VAL", "git config --file=FILE" and "git config --blob=BLOB". As we are going to expose the scope names to end-users in the next step, let's rethink the half-cryptic "cmdline" and instead use a proper word "command" (the settings from three sources in this scope are all in effect only during a single invocation of a git command).

or something like that.

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 52

Quoted 10 lines
t/helper/test-config.c +2 -2
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";

The only externally observable effect of this patch is this output string from test-tool and we are not breaking end-user experience, but I am not sure if this churn is worth it. I dunno.

In any case, the change to t1308 we saw in the previous step belongs to this step, I think.

#36 lore raw

Re: [PATCH v3 4/4] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget
Quoted 41 lines · Matthew Rogers via GitGitGadget

+--show-scope::

Documentation/git-config.txt +4 -0
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +11 -0
index 52a904cfb1..d5931061e8 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -189,11 +191,43 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static const char *scope_to_string(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";

builtin/config.c static void show_config_origin(struct strbuf *buf) · line 212

Quoted 10 lines
builtin/config.c +10 -0
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}

It is a shame that with this defined in the main part of the system test-tool still needs to carry its own private copy.

I wonder if it results in a better system if we rename this to

const char *config_scope_name(enum config_scope scope)

made it externally visible, and use it in t/helper/test-config.c and get rid of the private copy scope_name() there?

Quoted 8 lines
config.h +0 -0
index f383a71404..91f851e925 100644
@@ -35,10 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 

config.h struct object_id; · line 47

Quoted 10 lines
config.h +10 -0
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+

And this is the logical place to make an external definition, if we were to go that route.

Quoted 10 lines
t/t1300-config.sh +2 -0
index 983a0a1583..b654a6d2f9 100755
@@ -1766,6 +1766,64 @@ test_expect_success !MINGW '--show-origin blob ref' '
 	test_cmp expect output
 '
 
+test_expect_success '--show-scope with --list' '
+	cat >expect <<-EOF &&

t/t1300-config.sh test_expect_success !MINGW '--show-origin blob ref' ' · line 1780

Quoted 10 lines
t/t1300-config.sh +10 -0
+		global	user.global=true
+		global	user.override=global
+		global	include.path=$INCLUDE_DIR/absolute.include
+		global	user.absolute=include
+		local	user.local=true
+		local	user.override=local
+		local	include.path=../include/relative.include
+		local	user.relative=include
+		command	user.cmdline=true
+	EOF

The HERE-DOC is over-indented. All the body lines should align with cat and EOF. The same comment applies to many "<<-" added by this patch---mimick the "<<-" that appear in earlier part of the same file.

t/t1300-config.sh test_expect_success !MINGW '--show-origin blob ref' ' · line 1792

Quoted 8 lines
t/t1300-config.sh +8 -0
+test_expect_success !MINGW '--show-scope with --blob' '
+	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
+	cat >expect <<-EOF &&
+		command	user.custom=true
+	EOF
+	git config --blob=$blob --show-scope --list >output &&
+	test_cmp expect output
+'

Missing blank line between two tests.

I wonder if we want to revamp the tests for --show-origin that wants to make sure a funny filename is quoted properly. For that purpose, CUSTOM_CONFIG_FILE is given a funny pathname, and it would have been OK to use that only for a single "do we quote properly?" test, but instead we use that same funnily-named file as the source in many places where we do not *care* how --show-origin quotes the pathname at all, and end up having to skip with !MINGW.

It's a bad tradition that started at 45bf3297 ("t1300: fix the new --show-origin tests on Windows", 2016-03-23), I guess, and is not a new problem introduced by this patch, but it should stop so that we can have a better test coverage everywhere.

Other than that, I think that the new feature added by this series is a sensible one. Thanks for working on it.

#37 lore raw

Re: [PATCH v3 4/4] config: add '--show-scope' to print the scope of a config value

Quoted 58 lines · Junio C Hamano
Quoted 41 lines · Matthew Rogers via GitGitGadget

+--show-scope::

Documentation/git-config.txt +4 -0
+     Similar to `--show-origin` in that it augments the output of
+     all queried config options with the scope of that value
+     (local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
      Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +11 -0
index 52a904cfb1..d5931061e8 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
      OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
      OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
      OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+     OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
      OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
      OPT_END(),
 };
@@ -189,11 +191,43 @@ static void show_config_origin(struct strbuf *buf)
      strbuf_addch(buf, term);
 }
 
+static const char *scope_to_string(enum config_scope scope)
+{
+     switch (scope) {
+     case CONFIG_SCOPE_LOCAL:
+             return "local";
+     case CONFIG_SCOPE_GLOBAL:
+             return "global";
+     case CONFIG_SCOPE_SYSTEM:
+             return "system";

builtin/config.c static void show_config_origin(struct strbuf *buf) · line 212

Quoted 10 lines
builtin/config.c +10 -0
+     case CONFIG_SCOPE_WORKTREE:
+             return "worktree";
+     case CONFIG_SCOPE_COMMAND:
+             return "command";
+     case CONFIG_SCOPE_SUBMODULE:
+             return "submodule";
+     default:
+             return "unknown";
+     }
+}

It is a shame that with this defined in the main part of the system test-tool still needs to carry its own private copy.

Quoted 7 lines

I wonder if it results in a better system if we rename this to

const char *config_scope_name(enum config_scope scope)

made it externally visible, and use it in t/helper/test-config.c and get rid of the private copy scope_name() there?

+1 and please keep the order in config_scope_name the same as in the enum definition. Will base my 'remote rename & branch.<name>.pushRemote' series on this then.

Bert

Quoted 75 lines
Quoted 8 lines
config.h +0 -0
index f383a71404..91f851e925 100644
@@ -35,10 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 

config.h struct object_id; · line 47

Quoted 10 lines
config.h +10 -0
+enum config_scope {
+     CONFIG_SCOPE_UNKNOWN = 0,
+     CONFIG_SCOPE_SYSTEM,
+     CONFIG_SCOPE_GLOBAL,
+     CONFIG_SCOPE_LOCAL,
+     CONFIG_SCOPE_WORKTREE,
+     CONFIG_SCOPE_COMMAND,
+     CONFIG_SCOPE_SUBMODULE,
+};
+

And this is the logical place to make an external definition, if we were to go that route.

Quoted 10 lines
t/t1300-config.sh +2 -0
index 983a0a1583..b654a6d2f9 100755
@@ -1766,6 +1766,64 @@ test_expect_success !MINGW '--show-origin blob ref' '
      test_cmp expect output
 '
 
+test_expect_success '--show-scope with --list' '
+     cat >expect <<-EOF &&

t/t1300-config.sh test_expect_success !MINGW '--show-origin blob ref' ' · line 1780

Quoted 10 lines
t/t1300-config.sh +10 -0
+             global  user.global=true
+             global  user.override=global
+             global  include.path=$INCLUDE_DIR/absolute.include
+             global  user.absolute=include
+             local   user.local=true
+             local   user.override=local
+             local   include.path=../include/relative.include
+             local   user.relative=include
+             command user.cmdline=true
+     EOF

The HERE-DOC is over-indented. All the body lines should align with cat and EOF. The same comment applies to many "<<-" added by this patch---mimick the "<<-" that appear in earlier part of the same file.

t/t1300-config.sh test_expect_success !MINGW '--show-origin blob ref' ' · line 1792

Quoted 8 lines
t/t1300-config.sh +8 -0
+test_expect_success !MINGW '--show-scope with --blob' '
+     blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
+     cat >expect <<-EOF &&
+             command user.custom=true
+     EOF
+     git config --blob=$blob --show-scope --list >output &&
+     test_cmp expect output
+'

Missing blank line between two tests.

I wonder if we want to revamp the tests for --show-origin that wants to make sure a funny filename is quoted properly. For that purpose, CUSTOM_CONFIG_FILE is given a funny pathname, and it would have been OK to use that only for a single "do we quote properly?" test, but instead we use that same funnily-named file as the source in many places where we do not *care* how --show-origin quotes the pathname at all, and end up having to skip with !MINGW.

It's a bad tradition that started at 45bf3297 ("t1300: fix the new --show-origin tests on Windows", 2016-03-23), I guess, and is not a new problem introduced by this patch, but it should stop so that we can have a better test coverage everywhere.

Other than that, I think that the new feature added by this series is a sensible one. Thanks for working on it.

#30 lore raw

Re: [PATCH v3 2/4] config: refine config scope enum

In reply to Junio C Hamano
Quoted 6 lines

So the gist of the change is to split REPO into two, LOCAL and WORKTREE.

If we can find a way to state that concisely, perhaps we can improve "refine enum" and make it more informative.

Should I just say "split repo scope" Or is that too on the nose?

Quoted 20 lines
Quoted 20 lines
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
              return "system";
      case CONFIG_SCOPE_GLOBAL:
              return "global";
-     case CONFIG_SCOPE_REPO:
+     case CONFIG_SCOPE_LOCAL:
              return "repo";
+     case CONFIG_SCOPE_WORKTREE:
+             return "worktree";
      case CONFIG_SCOPE_CMDLINE:
              return "cmdline";
      default:
t/t1308-config-set.sh +0 -0
index 7b4e1a63eb..535b2a73f7 100755
Quoted 8 lines

t/t1308-config-set.sh test_expect_success 'iteration shows correct origins' ' · line 268

Quoted 6 lines
t/t1308-config-set.sh +1 -1
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
      value=from-cmdline
      origin=command line
      name=
-     scope=cmdline
+     scope=command

Why???

I meant to put this change into the next series in the patch, but I must have messed up, so I'll readjust that.

Signature · 1 line
Matthew Rogers
#34 lore raw

Re: [PATCH v3 3/4] config: clarify meaning of command line scoping

In reply to Junio C Hamano
Quoted 3 lines

we have such a scope for one-shot settings and these three sources are already treated as the same class.

So this isn't technically correct, as before the final patch of this series we technically don't set the current_parsing_scope for those options. This doesn't actually affect anything though, because before then nothing actually checks the current_parsing_scope during such calls to git config. As such, it makes sense to me to keep that part of the commit message.

Quoted 16 lines
Quoted 3 lines

This patch introduces
CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

The change in this commit is to rename CMDLINE to COMMAND. That is what the proposed log message for this step must justify.

We internally use CONFIG_SCOPE_CMDLINE for the scope for the configuration variables that come from "git -c VAR=VAL", "git config --file=FILE" and "git config --blob=BLOB". As we are going to expose the scope names to end-users in the next step, let's rethink the half-cryptic "cmdline" and instead use a proper word "command" (the settings from three sources in this scope are all in effect only during a single invocation of a git command).

Quoted 1 line

or something like that.

I like this explanation much better so I'll roll that into the commit message.

Quoted 17 lines

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 52

Quoted 12 lines
t/helper/test-config.c +2 -2
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
              return "repo";
      case CONFIG_SCOPE_WORKTREE:
              return "worktree";
-     case CONFIG_SCOPE_CMDLINE:
-             return "cmdline";
+     case CONFIG_SCOPE_COMMAND:
+             return "command";

The only externally observable effect of this patch is this output string from test-tool and we are not breaking end-user experience, but I am not sure if this churn is worth it. I dunno.

Quoted 2 lines

In any case, the change to t1308 we saw in the previous step belongs to this step, I think.

Yeah, this was my bad...

Signature · 1 line
Matthew Rogers
#38 lore raw

Re: [PATCH v3 4/4] config: add '--show-scope' to print the scope of a config value

In reply to Junio C Hamano
Quoted 5 lines

The HERE-DOC is over-indented. All the body lines should align with cat and EOF. The same comment applies to many "<<-" added by this patch---mimick the "<<-" that appear in earlier part of the same file.

I was mimicking the style of the --show-origin tests, and didn't realize this was a style violation. This is done in a few tests, so I'll add a patch that just goes through the file and fixes that for the existing tests as well.

Quoted 8 lines

I wonder if we want to revamp the tests for --show-origin that wants to make sure a funny filename is quoted properly. For that purpose, CUSTOM_CONFIG_FILE is given a funny pathname, and it would have been OK to use that only for a single "do we quote properly?" test, but instead we use that same funnily-named file as the source in many places where we do not *care* how --show-origin quotes the pathname at all, and end up having to skip with !MINGW.

Quoted 5 lines

It's a bad tradition that started at 45bf3297 ("t1300: fix the new --show-origin tests on Windows", 2016-03-23), I guess, and is not a new problem introduced by this patch, but it should stop so that we can have a better test coverage everywhere.

Agreed.

Quoted 3 lines

Other than that, I think that the new feature added by this series is a sensible one. Thanks for working on it.

You're welcome! And thank you for the careful review.

Signature · 1 line
Matthew Rogers
#31 lore raw

Re: [PATCH v3 2/4] config: refine config scope enum

In reply to Matt Rogers
Quoted 8 lines · Matt Rogers
Quoted 6 lines

So the gist of the change is to split REPO into two, LOCAL and WORKTREE.

If we can find a way to state that concisely, perhaps we can improve "refine enum" and make it more informative.

Should I just say "split repo scope" Or is that too on the nose?

Yeah, I think phrasing along that line would work well.

config: split repo scope to local and worktree

That's 46 chars.

#40 lore raw

PATCH v4 1/6 config: fix typo in variable name

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#39 lore raw

v4 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v3:

* Cleaned up t1300
* Expanded test coverage for t1300 to not rely as much on !MINGW by using a simpler filename for most tests
* config_scope_name is now exposed in config.h
* cleaned up commit messages for clarity/content (again)

Matthew Rogers (6):
config: fix typo in variable name
t1300: fix over-indented HERE-DOCs
t1300: create custom config file without special characters
config: split repo scope to local and worktree
config: clarify meaning of command line scoping
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt |  15 ++-
 builtin/config.c             |  46 +++++--
 config.c                     |  35 ++++-
 config.h                     |  20 +--
 remote.c                     |   3 +-
 submodule-config.c           |   4 +-
 t/helper/test-config.c       |  17 +--
 t/t1300-config.sh            | 240 ++++++++++++++++++++++-------------
 t/t1308-config-set.sh        |   4 +-
 upload-pack.c                |   3 +-
 10 files changed, 248 insertions(+), 139 deletions(-)

base-commit: 232378479ee6c66206d47a9be175e3a39682aea6
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v3:

 1:  f5a81a4d25 = 1:  f5a81a4d25 config: fix typo in variable name
 -:  ---------- > 2:  1b42f85399 t1300: fix over-indented HERE-DOCs
 -:  ---------- > 3:  9d19794dfd t1300: create custom config file without special characters
 2:  f06f9291b7 ! 4:  9f160e281a config: refine config scope enum

@@ -1,6 +1,6 @@
Author: Matthew Rogers <[email protected]>

- config: refine config scope enum
+ config: split repo scope to local and worktree

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was
@@ -93,14 +93,14 @@
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@
+ value=from-repo
+ origin=file
+ name=.git/config
+- scope=repo
++ scope=local
+
+ key=foo.bar
value=from-cmdline
- origin=command line
- name=
-- scope=cmdline
-+ scope=command
- EOF
- GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
- test_cmp expect actual

diff --git a/upload-pack.c b/upload-pack.c
--- a/upload-pack.c
3: 97b8a7641d ! 5: 7f00f8559d config: clarify meaning of command line scoping
@@ -53,3 +53,16 @@
default:
return "unknown";
}
+
+ diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
+ --- a/t/t1308-config-set.sh
+ +++ b/t/t1308-config-set.sh
+@@
+ value=from-cmdline
+ origin=command line
+ name=
+- scope=cmdline
++ scope=command
+ EOF
+ GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
+ test_cmp expect actual
4: 61ff3c64b5 ! 6: 5549db7e39 config: add '--show-scope' to print the scope of a config value

     @@ -76,26 +76,6 @@
       	strbuf_addch(buf, term);
       }
       
     -+static const char *scope_to_string(enum config_scope scope)
     -+{
     -+	switch (scope) {
     -+	case CONFIG_SCOPE_LOCAL:
     -+		return "local";
     -+	case CONFIG_SCOPE_GLOBAL:
     -+		return "global";
     -+	case CONFIG_SCOPE_SYSTEM:
     -+		return "system";
     -+	case CONFIG_SCOPE_WORKTREE:
     -+		return "worktree";
     -+	case CONFIG_SCOPE_COMMAND:
     -+		return "command";
     -+	case CONFIG_SCOPE_SUBMODULE:
     -+		return "submodule";
     -+	default:
     -+		return "unknown";
     -+	}
     -+}
     -+
      +static void show_config_scope(struct strbuf *buf)
      +{
      +	const char term = end_nul ? '\0' : '\t';
     @@ -211,6 +191,33 @@
       	/*
       	 * If we have a specific filename, use it. Otherwise, follow the
       	 * regular lookup sequence.
     +@@
     + 	}
     + }
     + 
     ++const char *scope_to_string(enum config_scope scope)
     ++{
     ++	switch (scope) {
     ++	case CONFIG_SCOPE_SYSTEM:
     ++		return "system";
     ++	case CONFIG_SCOPE_GLOBAL:
     ++		return "global";
     ++	case CONFIG_SCOPE_LOCAL:
     ++		return "local";
     ++	case CONFIG_SCOPE_WORKTREE:
     ++		return "worktree";
     ++	case CONFIG_SCOPE_COMMAND:
     ++		return "command";
     ++	case CONFIG_SCOPE_SUBMODULE:
     ++		return "submodule";
     ++	default:
     ++		return "unknown";
     ++	}
     ++}
     ++
     + const char *current_config_name(void)
     + {
     + 	const char *name;
      
       diff --git a/config.h b/config.h
       --- a/config.h
     @@ -228,6 +235,7 @@
      +	CONFIG_SCOPE_COMMAND,
      +	CONFIG_SCOPE_SUBMODULE,
      +};
     ++const char *scope_to_string(enum config_scope scope);
      +
       struct git_config_source {
       	unsigned int use_stdin:1;
     @@ -273,14 +281,38 @@
       --- a/t/helper/test-config.c
       +++ b/t/helper/test-config.c
      @@
     - 		return "repo";
     - 	case CONFIG_SCOPE_WORKTREE:
     - 		return "worktree";
     -+	case CONFIG_SCOPE_SUBMODULE:
     -+		return "submodule";
     - 	case CONFIG_SCOPE_COMMAND:
     - 		return "command";
     - 	default:
     +  *
     +  */
     + 
     +-static const char *scope_name(enum config_scope scope)
     +-{
     +-	switch (scope) {
     +-	case CONFIG_SCOPE_SYSTEM:
     +-		return "system";
     +-	case CONFIG_SCOPE_GLOBAL:
     +-		return "global";
     +-	case CONFIG_SCOPE_LOCAL:
     +-		return "repo";
     +-	case CONFIG_SCOPE_WORKTREE:
     +-		return "worktree";
     +-	case CONFIG_SCOPE_COMMAND:
     +-		return "command";
     +-	default:
     +-		return "unknown";
     +-	}
     +-}
     + static int iterate_cb(const char *var, const char *value, void *data)
     + {
     + 	static int nr;
     +@@
     + 	printf("value=%s\n", value ? value : "(null)");
     + 	printf("origin=%s\n", current_config_origin_type());
     + 	printf("name=%s\n", current_config_name());
     +-	printf("scope=%s\n", scope_name(current_config_scope()));
     ++	printf("scope=%s\n", scope_to_string(current_config_scope()));
     + 
     + 	return 0;
     + }
      
       diff --git a/t/t1300-config.sh b/t/t1300-config.sh
       --- a/t/t1300-config.sh
     @@ -313,6 +345,7 @@
      +	git config --blob=$blob --show-scope --list >output &&
      +	test_cmp expect output
      +'
     ++
      +test_expect_success '--show-scope with --local' '
      +	cat >expect <<-\EOF &&
      +		local	user.local=true
Signature · 1 line
gitgitgadget
#41 lore raw

PATCH v4 2/6 t1300: fix over-indented HERE-DOCs

From: Matthew Rogers <[email protected]>

Prepare for the following patches by removing extraneous indents from HERE-DOCs used in config tests.

---
 t/t1300-config.sh | 168 +++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 84 deletions(-)
t/t1300-config.sh +84 -84
index 983a0a1583..e8b4575758 100755
@@ -1191,47 +1191,47 @@ test_expect_success 'old-fashioned settings are case insensitive' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		Qr = value2
+	[V.A]
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.a.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		QR = value2
+	[V.A]
+	QR = value2
 	EOF
 	git config -f testConfig_actual "V.a.R" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "V.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual
@@ -1241,26 +1241,26 @@ test_expect_success 'setting different case sensitive subsections ' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V "A"]
-		R = v1
-		[K "E"]
-		Y = v1
-		[a "b"]
-		c = v1
-		[d "e"]
-		f = v1
+	[V "A"]
+	R = v1
+	[K "E"]
+	Y = v1
+	[a "b"]
+	c = v1
+	[d "e"]
+	f = v1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V "A"]
-		Qr = v2
-		[K "E"]
-		Qy = v2
-		[a "b"]
-		Qc = v2
-		[d "e"]
-		f = v1
-		[d "E"]
-		Qf = v2
+	[V "A"]
+	Qr = v2
+	[K "E"]
+	Qy = v2
+	[a "b"]
+	Qc = v2
+	[d "e"]
+	f = v1
+	[d "E"]
+	Qf = v2
 	EOF
 	# exact match
 	git config -f testConfig_actual a.b.c v2 &&
@@ -1622,40 +1622,40 @@ test_expect_success 'set up --show-origin tests' '
 	INCLUDE_DIR="$HOME/include" &&
 	mkdir -p "$INCLUDE_DIR" &&
 	cat >"$INCLUDE_DIR"/absolute.include <<-\EOF &&
-		[user]
-			absolute = include
+	[user]
+		absolute = include
 	EOF
 	cat >"$INCLUDE_DIR"/relative.include <<-\EOF &&
-		[user]
-			relative = include
+	[user]
+		relative = include
 	EOF
 	cat >"$HOME"/.gitconfig <<-EOF &&
-		[user]
-			global = true
-			override = global
-		[include]
-			path = "$INCLUDE_DIR/absolute.include"
+	[user]
+		global = true
+		override = global
+	[include]
+		path = "$INCLUDE_DIR/absolute.include"
 	EOF
 	cat >.git/config <<-\EOF
-		[user]
-			local = true
-			override = local
-		[include]
-			path = ../include/relative.include
+	[user]
+		local = true
+		override = local
+	[include]
+		path = ../include/relative.include
 	EOF
 '
 
 test_expect_success '--show-origin with --list' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global=true
-		file:$HOME/.gitconfig	user.override=global
-		file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
-		file:$INCLUDE_DIR/absolute.include	user.absolute=include
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
-		file:.git/../include/relative.include	user.relative=include
-		command line:	user.cmdline=true
+	file:$HOME/.gitconfig	user.global=true
+	file:$HOME/.gitconfig	user.override=global
+	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
+	file:.git/../include/relative.include	user.relative=include
+	command line:	user.cmdline=true
 	EOF
 	git -c user.cmdline=true config --list --show-origin >output &&
 	test_cmp expect output
@@ -1663,16 +1663,16 @@ test_expect_success '--show-origin with --list' '
 
 test_expect_success '--show-origin with --list --null' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfigQuser.global
-		trueQfile:$HOME/.gitconfigQuser.override
-		globalQfile:$HOME/.gitconfigQinclude.path
-		$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
-		includeQfile:.git/configQuser.local
-		trueQfile:.git/configQuser.override
-		localQfile:.git/configQinclude.path
-		../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
-		includeQcommand line:Quser.cmdline
-		trueQ
+	file:$HOME/.gitconfigQuser.global
+	trueQfile:$HOME/.gitconfigQuser.override
+	globalQfile:$HOME/.gitconfigQinclude.path
+	$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
+	includeQfile:.git/configQuser.local
+	trueQfile:.git/configQuser.override
+	localQfile:.git/configQinclude.path
+	../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
+	includeQcommand line:Quser.cmdline
+	trueQ
 	EOF
 	git -c user.cmdline=true config --null --list --show-origin >output.raw &&
 	nul_to_q <output.raw >output &&
@@ -1684,9 +1684,9 @@ test_expect_success '--show-origin with --list --null' '
 
 test_expect_success '--show-origin with single file' '
 	cat >expect <<-\EOF &&
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
 	EOF
 	git config --local --list --show-origin >output &&
 	test_cmp expect output
@@ -1694,8 +1694,8 @@ test_expect_success '--show-origin with single file' '
 
 test_expect_success '--show-origin with --get-regexp' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global true
-		file:.git/config	user.local true
+	file:$HOME/.gitconfig	user.global true
+	file:.git/config	user.local true
 	EOF
 	git config --show-origin --get-regexp "user\.[g|l].*" >output &&
 	test_cmp expect output
@@ -1703,7 +1703,7 @@ test_expect_success '--show-origin with --get-regexp' '
 
 test_expect_success '--show-origin getting a single key' '
 	cat >expect <<-\EOF &&
-		file:.git/config	local
+	file:.git/config	local
 	EOF
 	git config --show-origin user.override >output &&
 	test_cmp expect output
@@ -1712,14 +1712,14 @@ test_expect_success '--show-origin getting a single key' '
 test_expect_success 'set up custom config file' '
 	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
-		[user]
-			custom = true
+	[user]
+		custom = true
 	EOF
 '
 
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
-		file:"file\" (dq) and spaces.conf"	user.custom=true
+	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
 	test_cmp expect output
@@ -1727,7 +1727,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' '
 
 test_expect_success '--show-origin stdin' '
 	cat >expect <<-\EOF &&
-		standard input:	user.custom=true
+	standard input:	user.custom=true
 	EOF
 	git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
 	test_cmp expect output
@@ -1735,11 +1735,11 @@ test_expect_success '--show-origin stdin' '
 
 test_expect_success '--show-origin stdin with file include' '
 	cat >"$INCLUDE_DIR"/stdin.include <<-EOF &&
-		[user]
-			stdin = include
+	[user]
+		stdin = include
 	EOF
 	cat >expect <<-EOF &&
-		file:$INCLUDE_DIR/stdin.include	include
+	file:$INCLUDE_DIR/stdin.include	include
 	EOF
 	echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
 	git config --show-origin --includes --file - user.stdin >output &&
@@ -1750,7 +1750,7 @@ test_expect_success '--show-origin stdin with file include' '
 test_expect_success !MINGW '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
-		blob:$blob	user.custom=true
+	blob:$blob	user.custom=true
 	EOF
 	git config --blob=$blob --show-origin --list >output &&
 	test_cmp expect output
@@ -1758,7 +1758,7 @@ test_expect_success !MINGW '--show-origin blob' '
 
 test_expect_success !MINGW '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-		blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#43 lore raw

PATCH v4 3/6 t1300: create custom config file without special characters

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Tests that required a custom configuration file to be created previously used a file with non-alphanumeric characters including escaped double quotes. This is not really necessary for the majority of tests involving custom config files, and decreases test coverage on systems that dissallow such filenames (Windows, etc.).

Create two files, one appropriate for testing quoting and one appropriate for general use.

---
 t/t1300-config.sh | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
t/t1300-config.sh +10 -5
index e8b4575758..e5fb9114f6 100755
@@ -1710,18 +1710,23 @@ test_expect_success '--show-origin getting a single key' '
 '
 
 test_expect_success 'set up custom config file' '
-	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
+	CUSTOM_CONFIG_FILE="custom.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
 	[user]
 		custom = true
 	EOF
 '
 
+test_expect_success !MINGW 'set up custom config file with special name characters' '
+	WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
+	cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
+'
+
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
 	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
-	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
+	git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
 	test_cmp expect output
 '
 
@@ -1747,7 +1752,7 @@ test_expect_success '--show-origin stdin with file include' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob' '
+test_expect_success '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
 	blob:$blob	user.custom=true
@@ -1756,9 +1761,9 @@ test_expect_success !MINGW '--show-origin blob' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob ref' '
+test_expect_success '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:master:custom.conf	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#48 lore raw

PATCH v4 5/6 config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 t/t1308-config-set.sh  | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 6695e463eb..78bbb9eb98 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
t/t1308-config-set.sh +1 -1
index 90196e2862..fba0abe429 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
Signature · 1 line
gitgitgadget
#45 lore raw

PATCH v4 4/6 config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 t/t1308-config-set.sh  | 2 +-
 upload-pack.c          | 3 ++-
 6 files changed, 12 insertions(+), 10 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#49 lore raw

PATCH v4 6/6 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++---
 builtin/config.c             | 36 +++++++++++++++++++---
 config.c                     | 26 +++++++++++++++-
 config.h                     | 21 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       | 19 +-----------
 t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
 7 files changed, 141 insertions(+), 39 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +31 -5
index 52a904cfb1..66d2b0d2df 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -189,11 +191,23 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = scope_to_string(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);
@@ -213,6 +227,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_scope(buf);
 	if (show_origin)
 		show_config_origin(buf);
 	if (show_keys)
@@ -622,6 +638,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
 		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
 	if (use_global_config) {
@@ -637,6 +654,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			 */
 			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
 		if (access_or_warn(user_config, R_OK, 0) &&
 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
 			given_config_source.file = xdg_config;
@@ -646,11 +665,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			free(xdg_config);
 		}
 	}
-	else if (use_system_config)
+	else if (use_system_config) {
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
 		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
 		struct worktree **worktrees = get_worktrees(0);
 		if (repository_format_worktree_config)
 			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +683,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			      "section in \"git help worktree\" for details"));
 		else
 			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
+
 	if (respect_includes_opt == -1)
 		config_options.respect_includes = !given_config_source.file;
 	else
config.c +25 -1
index f319a3d6a0..469dff57b4 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
@@ -3294,6 +3298,26 @@ const char *current_config_origin_type(void)
 	}
 }
 
+const char *scope_to_string(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}
+
 const char *current_config_name(void)
 {
 	const char *name;
config.h +12 -9
index f383a71404..7b3aec0092 100644
@@ -35,10 +35,22 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+const char *scope_to_string(enum config_scope scope);
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +306,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +1 -18
index 78bbb9eb98..2e91879b2a 100644
@@ -37,23 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_LOCAL:
-		return "repo";
-	case CONFIG_SCOPE_WORKTREE:
-		return "worktree";
-	case CONFIG_SCOPE_COMMAND:
-		return "command";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -65,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", scope_to_string(current_config_scope()));
 
 	return 0;
 }
t/t1300-config.sh +59 -0

65 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#42 lore raw

Re: [PATCH v4 2/6] t1300: fix over-indented HERE-DOCs

In reply to Matthew Rogers via GitGitGadget
Quoted 9 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Prepare for the following patches by removing extraneous indents from HERE-DOCs used in config tests.

---
 t/t1300-config.sh | 168 +++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 84 deletions(-)

This step is new. It makes sense, I think.

Thanks.

#44 lore raw

Re: [PATCH v4 3/6] t1300: create custom config file without special characters

In reply to Matthew Rogers via GitGitGadget
Quoted 10 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Tests that required a custom configuration file to be created previously used a file with non-alphanumeric characters including escaped double quotes. This is not really necessary for the majority of tests involving custom config files, and decreases test coverage on systems that dissallow such filenames (Windows, etc.).

Create two files, one appropriate for testing quoting and one appropriate for general use.

Nicely done.

Quoted 16 lines
---
 t/t1300-config.sh | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
t/t1300-config.sh +1 -1
index e8b4575758..e5fb9114f6 100755
@@ -1710,18 +1710,23 @@ test_expect_success '--show-origin getting a single key' '
 '
 
 test_expect_success 'set up custom config file' '
-	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
+	CUSTOM_CONFIG_FILE="custom.conf" &&

t/t1300-config.sh test_expect_success '--show-origin getting a single key' ' · line 1723

Quoted 10 lines
t/t1300-config.sh +4 -0
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
 	[user]
 		custom = true
 	EOF
 '
 
+test_expect_success !MINGW 'set up custom config file with special name characters' '
+	WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
+	cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
+'

OK.

Quoted 20 lines
t/t1300-config.sh +2 -2
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
 	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
-	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
+	git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
 	test_cmp expect output
 '
 
@@ -1747,7 +1752,7 @@ test_expect_success '--show-origin stdin with file include' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob' '
+test_expect_success '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
 	blob:$blob	user.custom=true
@@ -1756,9 +1761,9 @@ test_expect_success !MINGW '--show-origin blob' '
 	test_cmp expect output

t/t1300-config.sh test_expect_success !MINGW '--show-origin blob' ' · line 1769

Quoted 10 lines
t/t1300-config.sh +2 -2
 '
 
-test_expect_success !MINGW '--show-origin blob ref' '
+test_expect_success '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:master:custom.conf	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&

Nice to see these cleaned up.

#46 lore raw

Re: [PATCH v4 4/6] config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget
Quoted 22 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

Quoted 8 lines
---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 t/t1308-config-set.sh  | 2 +-
 upload-pack.c          | 3 ++-
 6 files changed, 12 insertions(+), 10 deletions(-)

Nicely done.

t/t1308-config-set.sh test_expect_success 'iteration shows correct origins' ' · line 265

Quoted 13 lines
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline

OK.

#47 lore raw

Re: [PATCH v4 4/6] config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 48

Quoted 11 lines · Matthew Rogers via GitGitGadget
t/helper/test-config.c +1 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";

This must be updated to "local", no, to match the change to t1308?

Quoted 15 lines
t/helper/test-config.c +2 -0
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
#50 lore raw

Re: [PATCH v4 6/6] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

config.c const char *current_config_origin_type(void) · line 3309

Quoted 9 lines · Matthew Rogers via GitGitGadget
config.c +9 -0
+const char *scope_to_string(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";

Despite the screw-up at an earlier step, this one is correct ;-)

Quoted 22 lines
config.c +11 -0
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}
+
t/t1300-config.sh +2 -0
index e5fb9114f6..79dbea9bd1 100755
@@ -1771,6 +1771,65 @@ test_expect_success '--show-origin blob ref' '
 	test_cmp expect output
 '
 
+test_expect_success '--show-scope with --list' '
+	cat >expect <<-EOF &&

t/t1300-config.sh test_expect_success '--show-origin blob ref' ' · line 1785

Quoted 10 lines
t/t1300-config.sh +10 -0
+		global	user.global=true
+		global	user.override=global
+		global	include.path=$INCLUDE_DIR/absolute.include
+		global	user.absolute=include
+		local	user.local=true
+		local	user.override=local
+		local	include.path=../include/relative.include
+		local	user.relative=include
+		command	user.cmdline=true
+	EOF

We cleaned up the existing ones that are overly indented from this script in an earlier step. Let's not re-introduce them.

#54 lore raw
In reply to Matthew Rogers via GitGitGadget
Quoted 4 lines · Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

These generally look very good.

I'll queue them with proposed fix-ups, so please do not waste your time by reworking on your patches in response to my review comments before fetching today's integration result from the public repository, which probably will happen in 5 hours or so.

Thanks.

#51 lore raw

Re: [PATCH v4 6/6] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget
Quoted 9 lines · Matthew Rogers via GitGitGadget
config.c +9 -0
+const char *scope_to_string(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";

config.c const char *current_config_origin_type(void) · line 3319

Quoted 10 lines
config.c +10 -0
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}

In earlier round(s), this was called config_scope_name(), wasn't it?

"scope_to_string()" is a much worse than "config_scope_name()" as a name of a global function (e.g. we won't know what subsystems other than "config" may want to use "scope"). As you remember, Bert's "remote rename" series wants to use a public interface like this function, and the series expects this function to be called config_scope_name(). Let's not rename a public API function suddenly---it disrupts other topics in flight.

Thanks.

#52 lore raw

Re: [PATCH v4 6/6] config: add '--show-scope' to print the scope of a config value

I think this was a mess-up on my end. I had meant to rename it to config_scope_name() (after talking with Bert) but it appears that I had messed up, so I think my mistake wasn't to rename the function, but to fail to rename it. So I do apologize.

Quoted 34 lines · Junio C Hamano
Quoted 9 lines · Matthew Rogers via GitGitGadget
config.c +9 -0
+const char *scope_to_string(enum config_scope scope)
+{
+     switch (scope) {
+     case CONFIG_SCOPE_SYSTEM:
+             return "system";
+     case CONFIG_SCOPE_GLOBAL:
+             return "global";
+     case CONFIG_SCOPE_LOCAL:
+             return "local";

config.c const char *current_config_origin_type(void) · line 3319

Quoted 10 lines
config.c +10 -0
+     case CONFIG_SCOPE_WORKTREE:
+             return "worktree";
+     case CONFIG_SCOPE_COMMAND:
+             return "command";
+     case CONFIG_SCOPE_SUBMODULE:
+             return "submodule";
+     default:
+             return "unknown";
+     }
+}

In earlier round(s), this was called config_scope_name(), wasn't it?

"scope_to_string()" is a much worse than "config_scope_name()" as a name of a global function (e.g. we won't know what subsystems other than "config" may want to use "scope"). As you remember, Bert's "remote rename" series wants to use a public interface like this function, and the series expects this function to be called config_scope_name(). Let's not rename a public API function suddenly---it disrupts other topics in flight.

Thanks.

Signature · 1 line
Matthew Rogers
#53 lore raw

Re: [PATCH v4 6/6] config: add '--show-scope' to print the scope of a config value

Quoted 4 lines · Matt Rogers

I think this was a mess-up on my end. I had meant to rename it to config_scope_name() (after talking with Bert) but it appears that I had messed up, so I think my mistake wasn't to rename the function, but to fail to rename it. So I do apologize.

No need to. I just wanted to make sure everybody involved is aware of what others are doing to avoid wasted effort.

Now I do expect the (hopefully) final reroll of your topic, so that Bert can fork his topic on top of it.

Thanks.

#55 lore raw

v5 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v3:

* Cleaned up t1300
* Expanded test coverage for t1300 to not rely as much on !MINGW by using a simpler filename for most tests
* config_scope_name is now exposed in config.h
* cleaned up commit messages for clarity/content (again)

Matthew Rogers (6):
config: fix typo in variable name
t1300: fix over-indented HERE-DOCs
t1300: create custom config file without special characters
config: split repo scope to local and worktree
config: clarify meaning of command line scoping
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt |  15 ++-
 builtin/config.c             |  46 +++++--
 config.c                     |  35 ++++-
 config.h                     |  20 +--
 remote.c                     |   3 +-
 submodule-config.c           |   4 +-
 t/helper/test-config.c       |  17 +--
 t/t1300-config.sh            | 240 ++++++++++++++++++++++-------------
 t/t1308-config-set.sh        |   4 +-
 upload-pack.c                |   3 +-
 10 files changed, 248 insertions(+), 139 deletions(-)

base-commit: 232378479ee6c66206d47a9be175e3a39682aea6
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v4:

 1:  f5a81a4d25 = 1:  f5a81a4d25 config: fix typo in variable name
 2:  1b42f85399 = 2:  1b42f85399 t1300: fix over-indented HERE-DOCs
 3:  9d19794dfd = 3:  9d19794dfd t1300: create custom config file without special characters
 4:  9f160e281a = 4:  9f160e281a config: split repo scope to local and worktree
 5:  7f00f8559d = 5:  7f00f8559d config: clarify meaning of command line scoping
 6:  5549db7e39 = 6:  2e979d9fa5 config: add '--show-scope' to print the scope of a config value
Signature · 1 line
gitgitgadget
#56 lore raw

PATCH v5 1/6 config: fix typo in variable name

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#57 lore raw

PATCH v5 2/6 t1300: fix over-indented HERE-DOCs

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Prepare for the following patches by removing extraneous indents from HERE-DOCs used in config tests.

---
 t/t1300-config.sh | 168 +++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 84 deletions(-)
t/t1300-config.sh +84 -84
index 983a0a1583..e8b4575758 100755
@@ -1191,47 +1191,47 @@ test_expect_success 'old-fashioned settings are case insensitive' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		Qr = value2
+	[V.A]
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.a.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		QR = value2
+	[V.A]
+	QR = value2
 	EOF
 	git config -f testConfig_actual "V.a.R" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "V.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual
@@ -1241,26 +1241,26 @@ test_expect_success 'setting different case sensitive subsections ' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V "A"]
-		R = v1
-		[K "E"]
-		Y = v1
-		[a "b"]
-		c = v1
-		[d "e"]
-		f = v1
+	[V "A"]
+	R = v1
+	[K "E"]
+	Y = v1
+	[a "b"]
+	c = v1
+	[d "e"]
+	f = v1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V "A"]
-		Qr = v2
-		[K "E"]
-		Qy = v2
-		[a "b"]
-		Qc = v2
-		[d "e"]
-		f = v1
-		[d "E"]
-		Qf = v2
+	[V "A"]
+	Qr = v2
+	[K "E"]
+	Qy = v2
+	[a "b"]
+	Qc = v2
+	[d "e"]
+	f = v1
+	[d "E"]
+	Qf = v2
 	EOF
 	# exact match
 	git config -f testConfig_actual a.b.c v2 &&
@@ -1622,40 +1622,40 @@ test_expect_success 'set up --show-origin tests' '
 	INCLUDE_DIR="$HOME/include" &&
 	mkdir -p "$INCLUDE_DIR" &&
 	cat >"$INCLUDE_DIR"/absolute.include <<-\EOF &&
-		[user]
-			absolute = include
+	[user]
+		absolute = include
 	EOF
 	cat >"$INCLUDE_DIR"/relative.include <<-\EOF &&
-		[user]
-			relative = include
+	[user]
+		relative = include
 	EOF
 	cat >"$HOME"/.gitconfig <<-EOF &&
-		[user]
-			global = true
-			override = global
-		[include]
-			path = "$INCLUDE_DIR/absolute.include"
+	[user]
+		global = true
+		override = global
+	[include]
+		path = "$INCLUDE_DIR/absolute.include"
 	EOF
 	cat >.git/config <<-\EOF
-		[user]
-			local = true
-			override = local
-		[include]
-			path = ../include/relative.include
+	[user]
+		local = true
+		override = local
+	[include]
+		path = ../include/relative.include
 	EOF
 '
 
 test_expect_success '--show-origin with --list' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global=true
-		file:$HOME/.gitconfig	user.override=global
-		file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
-		file:$INCLUDE_DIR/absolute.include	user.absolute=include
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
-		file:.git/../include/relative.include	user.relative=include
-		command line:	user.cmdline=true
+	file:$HOME/.gitconfig	user.global=true
+	file:$HOME/.gitconfig	user.override=global
+	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
+	file:.git/../include/relative.include	user.relative=include
+	command line:	user.cmdline=true
 	EOF
 	git -c user.cmdline=true config --list --show-origin >output &&
 	test_cmp expect output
@@ -1663,16 +1663,16 @@ test_expect_success '--show-origin with --list' '
 
 test_expect_success '--show-origin with --list --null' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfigQuser.global
-		trueQfile:$HOME/.gitconfigQuser.override
-		globalQfile:$HOME/.gitconfigQinclude.path
-		$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
-		includeQfile:.git/configQuser.local
-		trueQfile:.git/configQuser.override
-		localQfile:.git/configQinclude.path
-		../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
-		includeQcommand line:Quser.cmdline
-		trueQ
+	file:$HOME/.gitconfigQuser.global
+	trueQfile:$HOME/.gitconfigQuser.override
+	globalQfile:$HOME/.gitconfigQinclude.path
+	$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
+	includeQfile:.git/configQuser.local
+	trueQfile:.git/configQuser.override
+	localQfile:.git/configQinclude.path
+	../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
+	includeQcommand line:Quser.cmdline
+	trueQ
 	EOF
 	git -c user.cmdline=true config --null --list --show-origin >output.raw &&
 	nul_to_q <output.raw >output &&
@@ -1684,9 +1684,9 @@ test_expect_success '--show-origin with --list --null' '
 
 test_expect_success '--show-origin with single file' '
 	cat >expect <<-\EOF &&
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
 	EOF
 	git config --local --list --show-origin >output &&
 	test_cmp expect output
@@ -1694,8 +1694,8 @@ test_expect_success '--show-origin with single file' '
 
 test_expect_success '--show-origin with --get-regexp' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global true
-		file:.git/config	user.local true
+	file:$HOME/.gitconfig	user.global true
+	file:.git/config	user.local true
 	EOF
 	git config --show-origin --get-regexp "user\.[g|l].*" >output &&
 	test_cmp expect output
@@ -1703,7 +1703,7 @@ test_expect_success '--show-origin with --get-regexp' '
 
 test_expect_success '--show-origin getting a single key' '
 	cat >expect <<-\EOF &&
-		file:.git/config	local
+	file:.git/config	local
 	EOF
 	git config --show-origin user.override >output &&
 	test_cmp expect output
@@ -1712,14 +1712,14 @@ test_expect_success '--show-origin getting a single key' '
 test_expect_success 'set up custom config file' '
 	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
-		[user]
-			custom = true
+	[user]
+		custom = true
 	EOF
 '
 
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
-		file:"file\" (dq) and spaces.conf"	user.custom=true
+	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
 	test_cmp expect output
@@ -1727,7 +1727,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' '
 
 test_expect_success '--show-origin stdin' '
 	cat >expect <<-\EOF &&
-		standard input:	user.custom=true
+	standard input:	user.custom=true
 	EOF
 	git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
 	test_cmp expect output
@@ -1735,11 +1735,11 @@ test_expect_success '--show-origin stdin' '
 
 test_expect_success '--show-origin stdin with file include' '
 	cat >"$INCLUDE_DIR"/stdin.include <<-EOF &&
-		[user]
-			stdin = include
+	[user]
+		stdin = include
 	EOF
 	cat >expect <<-EOF &&
-		file:$INCLUDE_DIR/stdin.include	include
+	file:$INCLUDE_DIR/stdin.include	include
 	EOF
 	echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
 	git config --show-origin --includes --file - user.stdin >output &&
@@ -1750,7 +1750,7 @@ test_expect_success '--show-origin stdin with file include' '
 test_expect_success !MINGW '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
-		blob:$blob	user.custom=true
+	blob:$blob	user.custom=true
 	EOF
 	git config --blob=$blob --show-origin --list >output &&
 	test_cmp expect output
@@ -1758,7 +1758,7 @@ test_expect_success !MINGW '--show-origin blob' '
 
 test_expect_success !MINGW '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-		blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#58 lore raw

PATCH v5 3/6 t1300: create custom config file without special characters

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Tests that required a custom configuration file to be created previously used a file with non-alphanumeric characters including escaped double quotes. This is not really necessary for the majority of tests involving custom config files, and decreases test coverage on systems that dissallow such filenames (Windows, etc.).

Create two files, one appropriate for testing quoting and one appropriate for general use.

---
 t/t1300-config.sh | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
t/t1300-config.sh +10 -5
index e8b4575758..e5fb9114f6 100755
@@ -1710,18 +1710,23 @@ test_expect_success '--show-origin getting a single key' '
 '
 
 test_expect_success 'set up custom config file' '
-	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
+	CUSTOM_CONFIG_FILE="custom.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
 	[user]
 		custom = true
 	EOF
 '
 
+test_expect_success !MINGW 'set up custom config file with special name characters' '
+	WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
+	cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
+'
+
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
 	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
-	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
+	git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
 	test_cmp expect output
 '
 
@@ -1747,7 +1752,7 @@ test_expect_success '--show-origin stdin with file include' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob' '
+test_expect_success '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
 	blob:$blob	user.custom=true
@@ -1756,9 +1761,9 @@ test_expect_success !MINGW '--show-origin blob' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob ref' '
+test_expect_success '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:master:custom.conf	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#61 lore raw

PATCH v5 5/6 config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 t/t1308-config-set.sh  | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 6695e463eb..78bbb9eb98 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "repo";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
t/t1308-config-set.sh +1 -1
index 90196e2862..fba0abe429 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
Signature · 1 line
gitgitgadget
#59 lore raw

PATCH v5 4/6 config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 4 +++-
 t/t1308-config-set.sh  | 2 +-
 upload-pack.c          | 3 ++-
 6 files changed, 12 insertions(+), 10 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#62 lore raw

PATCH v5 6/6 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++---
 builtin/config.c             | 36 +++++++++++++++++++---
 config.c                     | 26 +++++++++++++++-
 config.h                     | 21 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       | 19 +-----------
 t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
 7 files changed, 141 insertions(+), 39 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +31 -5
index 52a904cfb1..66d2b0d2df 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -189,11 +191,23 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = scope_to_string(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);
@@ -213,6 +227,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_scope(buf);
 	if (show_origin)
 		show_config_origin(buf);
 	if (show_keys)
@@ -622,6 +638,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
 		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
 	if (use_global_config) {
@@ -637,6 +654,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			 */
 			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
 		if (access_or_warn(user_config, R_OK, 0) &&
 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
 			given_config_source.file = xdg_config;
@@ -646,11 +665,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			free(xdg_config);
 		}
 	}
-	else if (use_system_config)
+	else if (use_system_config) {
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
 		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
 		struct worktree **worktrees = get_worktrees(0);
 		if (repository_format_worktree_config)
 			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +683,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			      "section in \"git help worktree\" for details"));
 		else
 			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
+
 	if (respect_includes_opt == -1)
 		config_options.respect_includes = !given_config_source.file;
 	else
config.c +25 -1
index f319a3d6a0..469dff57b4 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
@@ -3294,6 +3298,26 @@ const char *current_config_origin_type(void)
 	}
 }
 
+const char *scope_to_string(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}
+
 const char *current_config_name(void)
 {
 	const char *name;
config.h +12 -9
index f383a71404..7b3aec0092 100644
@@ -35,10 +35,22 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+const char *scope_to_string(enum config_scope scope);
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +306,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +1 -18
index 78bbb9eb98..2e91879b2a 100644
@@ -37,23 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_LOCAL:
-		return "repo";
-	case CONFIG_SCOPE_WORKTREE:
-		return "worktree";
-	case CONFIG_SCOPE_COMMAND:
-		return "command";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -65,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", scope_to_string(current_config_scope()));
 
 	return 0;
 }
t/t1300-config.sh +59 -0

65 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#60 lore raw

Re: [PATCH v5 4/6] config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

t/helper/test-config.c static const char *scope_name(enum config_scope scope) · line 50

Quoted 13 lines · Matthew Rogers via GitGitGadget
t/helper/test-config.c +3 -1
index 214003d5b2..6695e463eb 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
+	case CONFIG_SCOPE_LOCAL:
 		return "repo";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";

It used to be only "repo"; now we give either "repo" or "worktree".

t/t1308-config-set.sh test_expect_success 'iteration shows correct origins' ' · line 262

Quoted 13 lines
t/helper/test-config.c +0 -0
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local

But the test expects "local".

This patch cannot be correct. I recall fixing this manually when I queued the previous round to 'pu'. Please double check.

#63 lore raw

Re: [PATCH v5 6/6] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget
Quoted 51 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++---
 builtin/config.c             | 36 +++++++++++++++++++---
 config.c                     | 26 +++++++++++++++-
 config.h                     | 21 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       | 19 +-----------
 t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
 7 files changed, 141 insertions(+), 39 deletions(-)
Documentation/git-config.txt +5 -5
index 899e92a1c9..2e47765aab 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit

Documentation/git-config.txt Valid `<type>`'s include: · line 227

Quoted 6 lines
Documentation/git-config.txt +3 -0
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value 

There is a trailing SP on this line. I think I fixed it up when I queued the last round on 'pu'. Please double check.

Documentation/git-config.txt Valid `<type>`'s include: · line 228

Quoted 1 line
Documentation/git-config.txt +1 -0
+	const char *scope = scope_to_string(current_config_scope());

??? Are we using scope_to_string() back again?

I thought I queued a fix-up patch when I queued the last round on 'pu' to unblock the other topic that wanted to build on top. Please double check.

Thanks.

#64 lore raw

Re: [PATCH v5 6/6] config: add '--show-scope' to print the scope of a config value

Quoted 6 lines

There is a trailing SP on this line. I think I fixed it up when I queued the last round on 'pu'. Please double check.

Quoted 1 line

+ const char *scope = scope_to_string(current_config_scope());

Quoted 7 lines

??? Are we using scope_to_string() back again?

I thought I queued a fix-up patch when I queued the last round on 'pu' to unblock the other topic that wanted to build on top. Please double check.

Thanks.

I think I messed up when I pulled those changes...

I can get it all sorted out tomorrow after work

Signature · 1 line
Matthew Rogers
#65 lore raw

v6 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v4:

* final cleanups

Matthew Rogers (6):
config: fix typo in variable name
t1300: fix over-indented HERE-DOCs
t1300: create custom config file without special characters
config: split repo scope to local and worktree
config: clarify meaning of command line scoping
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt |  15 ++-
 builtin/config.c             |  46 +++++--
 config.c                     |  35 ++++-
 config.h                     |  20 +--
 remote.c                     |   3 +-
 submodule-config.c           |   4 +-
 t/helper/test-config.c       |  17 +--
 t/t1300-config.sh            | 240 ++++++++++++++++++++++-------------
 t/t1308-config-set.sh        |   4 +-
 upload-pack.c                |   3 +-
 10 files changed, 248 insertions(+), 139 deletions(-)

base-commit: c7a62075917b3340f908093f63f1161c44ed1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v5:

1: f5a81a4d25 ! 1: 18f92f70cf config: fix typo in variable name
@@ -8,6 +8,7 @@
malapropism is being fixed.

+ Signed-off-by: Junio C Hamano <[email protected]>

diff --git a/builtin/config.c b/builtin/config.c --- a/builtin/config.c
2: 1b42f85399 ! 2: dc7b3f3b96 t1300: fix over-indented HERE-DOCs
@@ -6,6 +6,7 @@
HERE-DOCs used in config tests.

+ Signed-off-by: Junio C Hamano <[email protected]>

diff --git a/t/t1300-config.sh b/t/t1300-config.sh
--- a/t/t1300-config.sh
3: 9d19794dfd ! 3: 975e652368 t1300: create custom config file without special characters
@@ -12,6 +12,7 @@
appropriate for general use.

+ Signed-off-by: Junio C Hamano <[email protected]>

diff --git a/t/t1300-config.sh b/t/t1300-config.sh
--- a/t/t1300-config.sh
4: 9f160e281a ! 4: 1e406ba430 config: split repo scope to local and worktree

     @@ -22,6 +22,7 @@
          CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.
      
          Signed-off-by: Matthew Rogers <[email protected]>
     +    Signed-off-by: Junio C Hamano <[email protected]>
      
       diff --git a/config.c b/config.c
       --- a/config.c
     @@ -81,8 +82,9 @@
       	case CONFIG_SCOPE_GLOBAL:
       		return "global";
      -	case CONFIG_SCOPE_REPO:
     +-		return "repo";
      +	case CONFIG_SCOPE_LOCAL:
     - 		return "repo";
     ++		return "local";
      +	case CONFIG_SCOPE_WORKTREE:
      +		return "worktree";
       	case CONFIG_SCOPE_CMDLINE:
 5:  7f00f8559d ! 5:  936ce91c62 config: clarify meaning of command line scoping
     @@ -12,6 +12,7 @@
          CONFIG_SCOPE_CMDLINE redundant.
      
          Signed-off-by: Matthew Rogers <[email protected]>
     +    Signed-off-by: Junio C Hamano <[email protected]>
      
       diff --git a/config.c b/config.c
       --- a/config.c
     @@ -43,7 +44,7 @@
       --- a/t/helper/test-config.c
       +++ b/t/helper/test-config.c
      @@
     - 		return "repo";
     + 		return "local";
       	case CONFIG_SCOPE_WORKTREE:
       		return "worktree";
      -	case CONFIG_SCOPE_CMDLINE:
 6:  2e979d9fa5 ! 6:  fc141e8689 config: add '--show-scope' to print the scope of a config value
     @@ -12,6 +12,7 @@
          parsing the '.gitmodules' file.
      
          Signed-off-by: Matthew Rogers <[email protected]>
     +    Signed-off-by: Junio C Hamano <[email protected]>
      
       diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
       --- a/Documentation/git-config.txt
     @@ -46,7 +47,7 @@
       
      +--show-scope::
      +	Similar to `--show-origin` in that it augments the output of
     -+	all queried config options with the scope of that value 
     ++	all queried config options with the scope of that value
      +	(local, global, system, command).
      +
       --get-colorbool name [stdout-is-tty]::
     @@ -79,7 +80,7 @@
      +static void show_config_scope(struct strbuf *buf)
      +{
      +	const char term = end_nul ? '\0' : '\t';
     -+	const char *scope = scope_to_string(current_config_scope());
     ++	const char *scope = config_scope_name(current_config_scope());
      +
      +	strbuf_addstr(buf, N_(scope));
      +	strbuf_addch(buf, term);
     @@ -195,7 +196,7 @@
       	}
       }
       
     -+const char *scope_to_string(enum config_scope scope)
     ++const char *config_scope_name(enum config_scope scope)
      +{
      +	switch (scope) {
      +	case CONFIG_SCOPE_SYSTEM:
     @@ -235,7 +236,7 @@
      +	CONFIG_SCOPE_COMMAND,
      +	CONFIG_SCOPE_SUBMODULE,
      +};
     -+const char *scope_to_string(enum config_scope scope);
     ++const char *config_scope_name(enum config_scope scope);
      +
       struct git_config_source {
       	unsigned int use_stdin:1;
     @@ -292,7 +293,7 @@
      -	case CONFIG_SCOPE_GLOBAL:
      -		return "global";
      -	case CONFIG_SCOPE_LOCAL:
     --		return "repo";
     +-		return "local";
      -	case CONFIG_SCOPE_WORKTREE:
      -		return "worktree";
      -	case CONFIG_SCOPE_COMMAND:
     @@ -309,7 +310,7 @@
       	printf("origin=%s\n", current_config_origin_type());
       	printf("name=%s\n", current_config_name());
      -	printf("scope=%s\n", scope_name(current_config_scope()));
     -+	printf("scope=%s\n", scope_to_string(current_config_scope()));
     ++	printf("scope=%s\n", config_scope_name(current_config_scope()));
       
       	return 0;
       }
     @@ -323,15 +324,15 @@
       
      +test_expect_success '--show-scope with --list' '
      +	cat >expect <<-EOF &&
     -+		global	user.global=true
     -+		global	user.override=global
     -+		global	include.path=$INCLUDE_DIR/absolute.include
     -+		global	user.absolute=include
     -+		local	user.local=true
     -+		local	user.override=local
     -+		local	include.path=../include/relative.include
     -+		local	user.relative=include
     -+		command	user.cmdline=true
     ++	global	user.global=true
     ++	global	user.override=global
     ++	global	include.path=$INCLUDE_DIR/absolute.include
     ++	global	user.absolute=include
     ++	local	user.local=true
     ++	local	user.override=local
     ++	local	include.path=../include/relative.include
     ++	local	user.relative=include
     ++	command	user.cmdline=true
      +	EOF
      +	git -c user.cmdline=true config --list --show-scope >output &&
      +	test_cmp expect output
     @@ -340,7 +341,7 @@
      +test_expect_success !MINGW '--show-scope with --blob' '
      +	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
      +	cat >expect <<-EOF &&
     -+		command	user.custom=true
     ++	command	user.custom=true
      +	EOF
      +	git config --blob=$blob --show-scope --list >output &&
      +	test_cmp expect output
     @@ -348,9 +349,9 @@
      +
      +test_expect_success '--show-scope with --local' '
      +	cat >expect <<-\EOF &&
     -+		local	user.local=true
     -+		local	user.override=local
     -+		local	include.path=../include/relative.include
     ++	local	user.local=true
     ++	local	user.override=local
     ++	local	include.path=../include/relative.include
      +	EOF
      +	git config --local --list --show-scope >output &&
      +	test_cmp expect output
     @@ -358,7 +359,7 @@
      +
      +test_expect_success '--show-scope getting a single value' '
      +	cat >expect <<-\EOF &&
     -+		local	true
     ++	local	true
      +	EOF
      +	git config --show-scope --get user.local >output &&
      +	test_cmp expect output
     @@ -366,15 +367,15 @@
      +
      +test_expect_success '--show-scope with --show-origin' '
      +	cat >expect <<-EOF &&
     -+		global	file:$HOME/.gitconfig	user.global=true
     -+		global	file:$HOME/.gitconfig	user.override=global
     -+		global	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
     -+		global	file:$INCLUDE_DIR/absolute.include	user.absolute=include
     -+		local	file:.git/config	user.local=true
     -+		local	file:.git/config	user.override=local
     -+		local	file:.git/config	include.path=../include/relative.include
     -+		local	file:.git/../include/relative.include	user.relative=include
     -+		command	command line:	user.cmdline=true
     ++	global	file:$HOME/.gitconfig	user.global=true
     ++	global	file:$HOME/.gitconfig	user.override=global
     ++	global	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
     ++	global	file:$INCLUDE_DIR/absolute.include	user.absolute=include
     ++	local	file:.git/config	user.local=true
     ++	local	file:.git/config	user.override=local
     ++	local	file:.git/config	include.path=../include/relative.include
     ++	local	file:.git/../include/relative.include	user.relative=include
     ++	command	command line:	user.cmdline=true
      +	EOF
      +	git -c user.cmdline=true config --list --show-origin --show-scope >output &&
      +	test_cmp expect output
Signature · 1 line
gitgitgadget
#66 lore raw

PATCH v6 1/6 config: fix typo in variable name

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#67 lore raw

PATCH v6 2/6 t1300: fix over-indented HERE-DOCs

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Prepare for the following patches by removing extraneous indents from HERE-DOCs used in config tests.

---
 t/t1300-config.sh | 168 +++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 84 deletions(-)
t/t1300-config.sh +84 -84
index 983a0a1583..e8b4575758 100755
@@ -1191,47 +1191,47 @@ test_expect_success 'old-fashioned settings are case insensitive' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		Qr = value2
+	[V.A]
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.a.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		QR = value2
+	[V.A]
+	QR = value2
 	EOF
 	git config -f testConfig_actual "V.a.R" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "V.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual
@@ -1241,26 +1241,26 @@ test_expect_success 'setting different case sensitive subsections ' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V "A"]
-		R = v1
-		[K "E"]
-		Y = v1
-		[a "b"]
-		c = v1
-		[d "e"]
-		f = v1
+	[V "A"]
+	R = v1
+	[K "E"]
+	Y = v1
+	[a "b"]
+	c = v1
+	[d "e"]
+	f = v1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V "A"]
-		Qr = v2
-		[K "E"]
-		Qy = v2
-		[a "b"]
-		Qc = v2
-		[d "e"]
-		f = v1
-		[d "E"]
-		Qf = v2
+	[V "A"]
+	Qr = v2
+	[K "E"]
+	Qy = v2
+	[a "b"]
+	Qc = v2
+	[d "e"]
+	f = v1
+	[d "E"]
+	Qf = v2
 	EOF
 	# exact match
 	git config -f testConfig_actual a.b.c v2 &&
@@ -1622,40 +1622,40 @@ test_expect_success 'set up --show-origin tests' '
 	INCLUDE_DIR="$HOME/include" &&
 	mkdir -p "$INCLUDE_DIR" &&
 	cat >"$INCLUDE_DIR"/absolute.include <<-\EOF &&
-		[user]
-			absolute = include
+	[user]
+		absolute = include
 	EOF
 	cat >"$INCLUDE_DIR"/relative.include <<-\EOF &&
-		[user]
-			relative = include
+	[user]
+		relative = include
 	EOF
 	cat >"$HOME"/.gitconfig <<-EOF &&
-		[user]
-			global = true
-			override = global
-		[include]
-			path = "$INCLUDE_DIR/absolute.include"
+	[user]
+		global = true
+		override = global
+	[include]
+		path = "$INCLUDE_DIR/absolute.include"
 	EOF
 	cat >.git/config <<-\EOF
-		[user]
-			local = true
-			override = local
-		[include]
-			path = ../include/relative.include
+	[user]
+		local = true
+		override = local
+	[include]
+		path = ../include/relative.include
 	EOF
 '
 
 test_expect_success '--show-origin with --list' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global=true
-		file:$HOME/.gitconfig	user.override=global
-		file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
-		file:$INCLUDE_DIR/absolute.include	user.absolute=include
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
-		file:.git/../include/relative.include	user.relative=include
-		command line:	user.cmdline=true
+	file:$HOME/.gitconfig	user.global=true
+	file:$HOME/.gitconfig	user.override=global
+	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
+	file:.git/../include/relative.include	user.relative=include
+	command line:	user.cmdline=true
 	EOF
 	git -c user.cmdline=true config --list --show-origin >output &&
 	test_cmp expect output
@@ -1663,16 +1663,16 @@ test_expect_success '--show-origin with --list' '
 
 test_expect_success '--show-origin with --list --null' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfigQuser.global
-		trueQfile:$HOME/.gitconfigQuser.override
-		globalQfile:$HOME/.gitconfigQinclude.path
-		$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
-		includeQfile:.git/configQuser.local
-		trueQfile:.git/configQuser.override
-		localQfile:.git/configQinclude.path
-		../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
-		includeQcommand line:Quser.cmdline
-		trueQ
+	file:$HOME/.gitconfigQuser.global
+	trueQfile:$HOME/.gitconfigQuser.override
+	globalQfile:$HOME/.gitconfigQinclude.path
+	$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
+	includeQfile:.git/configQuser.local
+	trueQfile:.git/configQuser.override
+	localQfile:.git/configQinclude.path
+	../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
+	includeQcommand line:Quser.cmdline
+	trueQ
 	EOF
 	git -c user.cmdline=true config --null --list --show-origin >output.raw &&
 	nul_to_q <output.raw >output &&
@@ -1684,9 +1684,9 @@ test_expect_success '--show-origin with --list --null' '
 
 test_expect_success '--show-origin with single file' '
 	cat >expect <<-\EOF &&
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
 	EOF
 	git config --local --list --show-origin >output &&
 	test_cmp expect output
@@ -1694,8 +1694,8 @@ test_expect_success '--show-origin with single file' '
 
 test_expect_success '--show-origin with --get-regexp' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global true
-		file:.git/config	user.local true
+	file:$HOME/.gitconfig	user.global true
+	file:.git/config	user.local true
 	EOF
 	git config --show-origin --get-regexp "user\.[g|l].*" >output &&
 	test_cmp expect output
@@ -1703,7 +1703,7 @@ test_expect_success '--show-origin with --get-regexp' '
 
 test_expect_success '--show-origin getting a single key' '
 	cat >expect <<-\EOF &&
-		file:.git/config	local
+	file:.git/config	local
 	EOF
 	git config --show-origin user.override >output &&
 	test_cmp expect output
@@ -1712,14 +1712,14 @@ test_expect_success '--show-origin getting a single key' '
 test_expect_success 'set up custom config file' '
 	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
-		[user]
-			custom = true
+	[user]
+		custom = true
 	EOF
 '
 
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
-		file:"file\" (dq) and spaces.conf"	user.custom=true
+	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
 	test_cmp expect output
@@ -1727,7 +1727,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' '
 
 test_expect_success '--show-origin stdin' '
 	cat >expect <<-\EOF &&
-		standard input:	user.custom=true
+	standard input:	user.custom=true
 	EOF
 	git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
 	test_cmp expect output
@@ -1735,11 +1735,11 @@ test_expect_success '--show-origin stdin' '
 
 test_expect_success '--show-origin stdin with file include' '
 	cat >"$INCLUDE_DIR"/stdin.include <<-EOF &&
-		[user]
-			stdin = include
+	[user]
+		stdin = include
 	EOF
 	cat >expect <<-EOF &&
-		file:$INCLUDE_DIR/stdin.include	include
+	file:$INCLUDE_DIR/stdin.include	include
 	EOF
 	echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
 	git config --show-origin --includes --file - user.stdin >output &&
@@ -1750,7 +1750,7 @@ test_expect_success '--show-origin stdin with file include' '
 test_expect_success !MINGW '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
-		blob:$blob	user.custom=true
+	blob:$blob	user.custom=true
 	EOF
 	git config --blob=$blob --show-origin --list >output &&
 	test_cmp expect output
@@ -1758,7 +1758,7 @@ test_expect_success !MINGW '--show-origin blob' '
 
 test_expect_success !MINGW '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-		blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#68 lore raw

PATCH v6 3/6 t1300: create custom config file without special characters

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Tests that required a custom configuration file to be created previously used a file with non-alphanumeric characters including escaped double quotes. This is not really necessary for the majority of tests involving custom config files, and decreases test coverage on systems that dissallow such filenames (Windows, etc.).

Create two files, one appropriate for testing quoting and one appropriate for general use.

---
 t/t1300-config.sh | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
t/t1300-config.sh +10 -5
index e8b4575758..e5fb9114f6 100755
@@ -1710,18 +1710,23 @@ test_expect_success '--show-origin getting a single key' '
 '
 
 test_expect_success 'set up custom config file' '
-	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
+	CUSTOM_CONFIG_FILE="custom.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
 	[user]
 		custom = true
 	EOF
 '
 
+test_expect_success !MINGW 'set up custom config file with special name characters' '
+	WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
+	cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
+'
+
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
 	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
-	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
+	git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
 	test_cmp expect output
 '
 
@@ -1747,7 +1752,7 @@ test_expect_success '--show-origin stdin with file include' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob' '
+test_expect_success '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
 	blob:$blob	user.custom=true
@@ -1756,9 +1761,9 @@ test_expect_success !MINGW '--show-origin blob' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob ref' '
+test_expect_success '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:master:custom.conf	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#70 lore raw

PATCH v6 5/6 config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

---
 config.c               | 2 +-
 config.h               | 2 +-
 t/helper/test-config.c | 4 ++--
 t/t1308-config-set.sh  | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)
config.c +1 -1
index 447a013a15..f319a3d6a0 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
config.h +1 -1
index 284d92fb0e..f383a71404 100644
@@ -300,7 +300,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 
 enum config_scope current_config_scope(void);
t/helper/test-config.c +2 -2
index 9c6ae7a8a7..56c1f6dfb6 100644
@@ -48,8 +48,8 @@ static const char *scope_name(enum config_scope scope)
 		return "local";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
t/t1308-config-set.sh +1 -1
index 90196e2862..fba0abe429 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
Signature · 1 line
gitgitgadget
#69 lore raw

PATCH v6 4/6 config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c               | 7 ++-----
 config.h               | 3 ++-
 remote.c               | 3 ++-
 t/helper/test-config.c | 6 ++++--
 t/t1308-config-set.sh  | 2 +-
 upload-pack.c          | 3 ++-
 6 files changed, 13 insertions(+), 11 deletions(-)
config.c +2 -5
index d75f88ca0c..447a013a15 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
config.h +2 -1
index 91fd4c5e96..284d92fb0e 100644
@@ -298,7 +298,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/helper/test-config.c +4 -2
index 214003d5b2..9c6ae7a8a7 100644
@@ -44,8 +44,10 @@ static const char *scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "cmdline";
 	default:
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..90196e2862 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#71 lore raw

PATCH v6 6/6 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++---
 builtin/config.c             | 36 +++++++++++++++++++---
 config.c                     | 26 +++++++++++++++-
 config.h                     | 21 +++++++------
 submodule-config.c           |  4 ++-
 t/helper/test-config.c       | 19 +-----------
 t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
 7 files changed, 141 insertions(+), 39 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..7573160f21 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +31 -5
index 52a904cfb1..ee4aef6a35 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -189,11 +191,23 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = config_scope_name(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);
@@ -213,6 +227,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_scope(buf);
 	if (show_origin)
 		show_config_origin(buf);
 	if (show_keys)
@@ -622,6 +638,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
 		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
 	if (use_global_config) {
@@ -637,6 +654,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			 */
 			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
 		if (access_or_warn(user_config, R_OK, 0) &&
 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
 			given_config_source.file = xdg_config;
@@ -646,11 +665,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			free(xdg_config);
 		}
 	}
-	else if (use_system_config)
+	else if (use_system_config) {
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
 		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
 		struct worktree **worktrees = get_worktrees(0);
 		if (repository_format_worktree_config)
 			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +683,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			      "section in \"git help worktree\" for details"));
 		else
 			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
+
 	if (respect_includes_opt == -1)
 		config_options.respect_includes = !given_config_source.file;
 	else
config.c +25 -1
index f319a3d6a0..18a6bdd9ff 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
@@ -3294,6 +3298,26 @@ const char *current_config_origin_type(void)
 	}
 }
 
+const char *config_scope_name(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}
+
 const char *current_config_name(void)
 {
 	const char *name;
config.h +12 -9
index f383a71404..fe0addb0dc 100644
@@ -35,10 +35,22 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+const char *config_scope_name(enum config_scope scope);
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -294,15 +306,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
t/helper/test-config.c +1 -18
index 56c1f6dfb6..1e3bc7c8f4 100644
@@ -37,23 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_LOCAL:
-		return "local";
-	case CONFIG_SCOPE_WORKTREE:
-		return "worktree";
-	case CONFIG_SCOPE_COMMAND:
-		return "command";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -65,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
 	return 0;
 }
t/t1300-config.sh +59 -0

65 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#72 lore raw

Re: [PATCH v6 6/6] config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

Dear Matthew,

Quoted 13 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

Quoted 9 lines
---
  Documentation/git-config.txt | 15 ++++++---
  builtin/config.c             | 36 +++++++++++++++++++---
  config.c                     | 26 +++++++++++++++-
  config.h                     | 21 +++++++------
  submodule-config.c           |  4 ++-
  t/helper/test-config.c       | 19 +-----------
  t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
  7 files changed, 141 insertions(+), 39 deletions(-)

for clarity, I think this patch should be split up further.

For example:

- moving an enum and adding a new entry should be avoided
- does the changes to '/config.c' fix something?
- exposing config_scope_name should have been done before PATCH 4/6 already

Best,
Bert

Quoted 373 lines
Documentation/git-config.txt +10 -5
index 899e92a1c9..7573160f21 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
  SYNOPSIS
  --------
  [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
  'git config' [<file-option>] [--type=<type>] --add name value
  'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
  'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
  'git config' [<file-option>] --unset name [value_regex]
  'git config' [<file-option>] --unset-all name [value_regex]
  'git config' [<file-option>] --rename-section old_name new_name
  'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
  'git config' [<file-option>] --get-color name [default]
  'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
  'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
  	the actual origin (config file path, ref, or blob id if
  	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value
+	(local, global, system, command).
+
  --get-colorbool name [stdout-is-tty]::
 
  	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +31 -5
index 52a904cfb1..ee4aef6a35 100644
@@ -33,6 +33,7 @@ static int end_nul;
  static int respect_includes_opt = -1;
  static struct config_options config_options;
  static int show_origin;
+static int show_scope;
 
  #define ACTION_GET (1<<0)
  #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
  	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
  	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
  	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
  	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
  	OPT_END(),
  };
@@ -189,11 +191,23 @@ static void show_config_origin(struct strbuf *buf)
  	strbuf_addch(buf, term);
  }
 
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = config_scope_name(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
  static int show_all_config(const char *key_, const char *value_, void *cb)
  {
-	if (show_origin) {
+	if (show_origin || show_scope) {
  		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
  		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
  		fwrite(buf.buf, 1, buf.len, stdout);
  		strbuf_release(&buf);
@@ -213,6 +227,8 @@ struct strbuf_list {
 
  static int format_config(struct strbuf *buf, const char *key_, const char *value_)
  {
+	if (show_scope)
+		show_config_scope(buf);
  	if (show_origin)
  		show_config_origin(buf);
  	if (show_keys)
@@ -622,6 +638,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
  			!strcmp(given_config_source.file, "-")) {
  		given_config_source.file = NULL;
  		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
  	}
 
  	if (use_global_config) {
@@ -637,6 +654,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
  			 */
  			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
  		if (access_or_warn(user_config, R_OK, 0) &&
  		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
  			given_config_source.file = xdg_config;
@@ -646,11 +665,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
  			free(xdg_config);
  		}
  	}
-	else if (use_system_config)
+	else if (use_system_config) {
  		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
  		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
  		struct worktree **worktrees = get_worktrees(0);
  		if (repository_format_worktree_config)
  			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +683,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
  			      "section in \"git help worktree\" for details"));
  		else
  			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
  		free_worktrees(worktrees);
  	} else if (given_config_source.file) {
  		if (!is_absolute_path(given_config_source.file) && prefix)
  			given_config_source.file =
  				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
  	}
 
+
  	if (respect_includes_opt == -1)
  		config_options.respect_includes = !given_config_source.file;
  	else
config.c +25 -1
index f319a3d6a0..18a6bdd9ff 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
  	char *xdg_config = xdg_config_home("config");
  	char *user_config = expand_user_path("~/.gitconfig", 0);
  	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
  	if (opts->commondir)
  		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
  	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
  		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
  	free(xdg_config);
  	free(user_config);
  	free(repo_config);
@@ -1762,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
  		data = &inc;
  	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
  	/*
  	 * If we have a specific filename, use it. Otherwise, follow the
  	 * regular lookup sequence.
@@ -3294,6 +3298,26 @@ const char *current_config_origin_type(void)
  	}
  }
 
+const char *config_scope_name(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
+	default:
+		return "unknown";
+	}
+}
+
  const char *current_config_name(void)
  {
  	const char *name;
config.h +12 -9
index f383a71404..fe0addb0dc 100644
@@ -35,10 +35,22 @@ struct object_id;
 
  #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
+};
+const char *config_scope_name(enum config_scope scope);
+
  struct git_config_source {
  	unsigned int use_stdin:1;
  	const char *file;
  	const char *blob;
+	enum config_scope scope;
  };
 
  enum config_origin_type {
@@ -294,15 +306,6 @@ int config_error_nonbool(const char *);
 
  int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-
  enum config_scope current_config_scope(void);
  const char *current_config_origin_type(void);
  const char *current_config_name(void);
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
  static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
  {
  	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
  		const struct config_options opts = { 0 };
  		struct object_id oid;
  		char *file;
t/helper/test-config.c +1 -18
index 56c1f6dfb6..1e3bc7c8f4 100644
@@ -37,23 +37,6 @@
   *
   */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_LOCAL:
-		return "local";
-	case CONFIG_SCOPE_WORKTREE:
-		return "worktree";
-	case CONFIG_SCOPE_COMMAND:
-		return "command";
-	default:
-		return "unknown";
-	}
-}
  static int iterate_cb(const char *var, const char *value, void *data)
  {
  	static int nr;
@@ -65,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
  	printf("value=%s\n", value ? value : "(null)");
  	printf("origin=%s\n", current_config_origin_type());
  	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
  	return 0;
  }
t/t1300-config.sh +59 -0
index e5fb9114f6..5464c46c18 100755
@@ -1771,6 +1771,65 @@ test_expect_success '--show-origin blob ref' '
  	test_cmp expect output
  '
 
+test_expect_success '--show-scope with --list' '
+	cat >expect <<-EOF &&
+	global	user.global=true
+	global	user.override=global
+	global	include.path=$INCLUDE_DIR/absolute.include
+	global	user.absolute=include
+	local	user.local=true
+	local	user.override=local
+	local	include.path=../include/relative.include
+	local	user.relative=include
+	command	user.cmdline=true
+	EOF
+	git -c user.cmdline=true config --list --show-scope >output &&
+	test_cmp expect output
+'
+
+test_expect_success !MINGW '--show-scope with --blob' '
+	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
+	cat >expect <<-EOF &&
+	command	user.custom=true
+	EOF
+	git config --blob=$blob --show-scope --list >output &&
+	test_cmp expect output
+'
+
+test_expect_success '--show-scope with --local' '
+	cat >expect <<-\EOF &&
+	local	user.local=true
+	local	user.override=local
+	local	include.path=../include/relative.include
+	EOF
+	git config --local --list --show-scope >output &&
+	test_cmp expect output
+'
+
+test_expect_success '--show-scope getting a single value' '
+	cat >expect <<-\EOF &&
+	local	true
+	EOF
+	git config --show-scope --get user.local >output &&
+	test_cmp expect output
+'
+
+test_expect_success '--show-scope with --show-origin' '
+	cat >expect <<-EOF &&
+	global	file:$HOME/.gitconfig	user.global=true
+	global	file:$HOME/.gitconfig	user.override=global
+	global	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+	global	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+	local	file:.git/config	user.local=true
+	local	file:.git/config	user.override=local
+	local	file:.git/config	include.path=../include/relative.include
+	local	file:.git/../include/relative.include	user.relative=include
+	command	command line:	user.cmdline=true
+	EOF
+	git -c user.cmdline=true config --list --show-origin --show-scope >output &&
+	test_cmp expect output
+'
+
  test_expect_success '--local requires a repo' '
  	# we expect 128 to ensure that we do not simply
  	# fail to find anything and return code "1"
#73 lore raw

Re: [PATCH v6 6/6] config: add '--show-scope' to print the scope of a config value

Quoted 6 lines

for clarity, I think this patch should be split up further.

For example:

- moving an enum and adding a new entry should be avoided

As far as adding a new entry, that could probably be done in a separate patch. The submodule scoping is correct (mostly so config options that come from submodule blobs have a sane value to set the new scope field of git_config_source), but moving it is unavoidable as I'd either have to move config_scope or git_config_source for this patch to work, and moving git_config_source seemed like a ton more work

Quoted 1 line

- does the changes to '/config.c' fix something?

Another thing, that in hindsight could probably be split out. The other changes do fix the fact that previously recursive calls to do_git_config_sequence() would blow awway the current_parsing_scope information for higher level callers. This is not super common, but does occur when --show-scope is used with the --blob option.

Quoted 1 line

- exposing config_scope_name should have been done before PATCH 4/6 already

If that's better/more convenient, I don't have a problem breaking that out and moving
it there.

Signature · 1 line
Matthew Rogers
#74 lore raw

Re: [PATCH v6 6/6] config: add '--show-scope' to print the scope of a config value

Quoted 21 lines · Matt Rogers
Quoted 5 lines

for clarity, I think this patch should be split up further.

For example:

- moving an enum and adding a new entry should be avoided

As far as adding a new entry, that could probably be done in a separate patch. The submodule scoping is correct (mostly so config options that come from submodule blobs have a sane value to set the new scope field of git_config_source), but moving it is unavoidable as I'd either have to move config_scope or git_config_source for this patch to work, and moving git_config_source seemed like a ton more work

Quoted 1 line

- does the changes to '/config.c' fix something?

Another thing, that in hindsight could probably be split out. The other changes do fix the fact that previously recursive calls to do_git_config_sequence() would blow awway the current_parsing_scope information for higher level callers. This is not super common, but does occur when --show-scope is used with the --blob option.

Quoted 5 lines
Quoted 1 line

- exposing config_scope_name should have been done before PATCH 4/6 already

If that's better/more convenient, I don't have a problem breaking that out and moving
it there.

Alright. Thanks for another round of review.

#77 lore raw

PATCH v7 1/10 config: fix typo in variable name

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

In git config use of the end_null variable to determine if we should be null terminating our output. While it is correct to say a string is "null terminated" the character is actually the "nul" character, so this malapropism is being fixed.

---
 builtin/config.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/config.c +5 -5
index 98d65bc0ad..52a904cfb1 100644
@@ -29,7 +29,7 @@ static int use_worktree_config;
 static struct git_config_source given_config_source;
 static int actions, type;
 static char *default_value;
-static int end_null;
+static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
 	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 	OPT_GROUP(N_("Other")),
-	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
@@ -178,11 +178,11 @@ static void check_argc(int argc, int min, int max)
 
 static void show_config_origin(struct strbuf *buf)
 {
-	const char term = end_null ? '\0' : '\t';
+	const char term = end_nul ? '\0' : '\t';
 
 	strbuf_addstr(buf, current_config_origin_type());
 	strbuf_addch(buf, ':');
-	if (end_null)
+	if (end_nul)
 		strbuf_addstr(buf, current_config_name());
 	else
 		quote_c_style(current_config_name(), buf, NULL, 0);
@@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		config_options.git_dir = get_git_dir();
 	}
 
-	if (end_null) {
+	if (end_nul) {
 		term = '\0';
 		delim = '\n';
 		key_delim = '\n';
Signature · 1 line
gitgitgadget
#76 lore raw

v7 cover config: allow user to know scope of config options

In reply to Matthew Rogers via GitGitGadget

This was originally a pull request to the git-for-windows repository
[https://github.com/git-for-windows/git/pull/2399]. It adds a new option --show-scope which would allow a user to see what scope a given configuration value has (sytem, local, global, etc.).

changes since v6: Split patch 6: config: add '--show-scope'... into several parts, including moving the exposure of config_scope_name into its own commit earlier in the series.

Matthew Rogers (10):
config: fix typo in variable name
t1300: fix over-indented HERE-DOCs
t1300: create custom config file without special characters
config: make scope_name non-static and rename it
config: split repo scope to local and worktree
config: clarify meaning of command line scoping
config: preserve scope in do_git_config_sequence
config: teach git_config_source to remember its scope
submodule-config: add subomdule config scope
config: add '--show-scope' to print the scope of a config value

 Documentation/git-config.txt |  15 ++-
 builtin/config.c             |  46 +++++--
 config.c                     |  35 ++++-
 config.h                     |  20 +--
 remote.c                     |   3 +-
 submodule-config.c           |   4 +-
 t/helper/test-config.c       |  17 +--
 t/t1300-config.sh            | 240 ++++++++++++++++++++++-------------
 t/t1308-config-set.sh        |   4 +-
 upload-pack.c                |   3 +-
 10 files changed, 248 insertions(+), 139 deletions(-)

base-commit: de93cc14ab7e8db7645d8dbe4fd2603f76d5851f
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-478%2FROGERSM94%2Fadd-config-flags-v7
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-478/ROGERSM94/add-config-flags-v7
Pull-Request: https://github.com/gitgitgadget/git/pull/478

Range-diff vs v6:

  1:  18f92f70cf =  1:  1c4faa7a36 config: fix typo in variable name
  2:  dc7b3f3b96 =  2:  2c38c72f89 t1300: fix over-indented HERE-DOCs
  3:  975e652368 =  3:  c832293ca7 t1300: create custom config file without special characters
  -:  ---------- >  4:  14b0f27819 config: make scope_name non-static and rename it
  4:  1e406ba430 !  5:  1af0237b8e config: split repo scope to local and worktree
     @@ -45,6 +45,19 @@
       	if (!opts->ignore_worktree && repository_format_worktree_config) {
       		char *path = git_pathdup("config.worktree");
       		if (!access_or_die(path, R_OK, 0))
     +@@
     + 		return "system";
     + 	case CONFIG_SCOPE_GLOBAL:
     + 		return "global";
     +-	case CONFIG_SCOPE_REPO:
     +-		return "repo";
     ++	case CONFIG_SCOPE_LOCAL:
     ++		return "local";
     ++	case CONFIG_SCOPE_WORKTREE:
     ++		return "worktree";
     + 	case CONFIG_SCOPE_CMDLINE:
     + 		return "command line";
     + 	default:
      
       diff --git a/config.h b/config.h
       --- a/config.h
     @@ -58,7 +71,7 @@
      +	CONFIG_SCOPE_WORKTREE,
       	CONFIG_SCOPE_CMDLINE,
       };
     - 
     + const char *config_scope_name(enum config_scope scope);
      
       diff --git a/remote.c b/remote.c
       --- a/remote.c
     @@ -74,23 +87,6 @@
       	if (!strcmp(subkey, "mirror"))
       		remote->mirror = git_config_bool(key, value);
      
     - diff --git a/t/helper/test-config.c b/t/helper/test-config.c
     - --- a/t/helper/test-config.c
     - +++ b/t/helper/test-config.c
     -@@
     - 		return "system";
     - 	case CONFIG_SCOPE_GLOBAL:
     - 		return "global";
     --	case CONFIG_SCOPE_REPO:
     --		return "repo";
     -+	case CONFIG_SCOPE_LOCAL:
     -+		return "local";
     -+	case CONFIG_SCOPE_WORKTREE:
     -+		return "worktree";
     - 	case CONFIG_SCOPE_CMDLINE:
     - 		return "cmdline";
     - 	default:
     -
       diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
       --- a/t/t1308-config-set.sh
       +++ b/t/t1308-config-set.sh

5: 936ce91c62 ! 6: 64c20d0556 config: clarify meaning of command line scoping
@@ -26,6 +26,17 @@
if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
die(_("unable to parse command-line config"));

+@@
+ return "local";
+ case CONFIG_SCOPE_WORKTREE:
+ return "worktree";
+- case CONFIG_SCOPE_CMDLINE:
+- return "command line";
++ case CONFIG_SCOPE_COMMAND:
++ return "command";
+ default:
+ return "unknown";
+ }

diff --git a/config.h b/config.h
--- a/config.h
@@ -37,23 +48,8 @@
- CONFIG_SCOPE_CMDLINE,
+ CONFIG_SCOPE_COMMAND,
};
+ const char *config_scope_name(enum config_scope scope);

- enum config_scope current_config_scope(void);
-
- diff --git a/t/helper/test-config.c b/t/helper/test-config.c
- --- a/t/helper/test-config.c
- +++ b/t/helper/test-config.c
-@@
- return "local";
- case CONFIG_SCOPE_WORKTREE:
- return "worktree";
-- case CONFIG_SCOPE_CMDLINE:
-- return "cmdline";
-+ case CONFIG_SCOPE_COMMAND:
-+ return "command";
- default:
- return "unknown";
- }

diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh --- a/t/t1308-config-set.sh
@@ -62,7 +58,7 @@
value=from-cmdline
origin=command line
name=
-- scope=cmdline
+- scope=command line
+ scope=command
EOF
GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&

  -:  ---------- >  7:  f61985375c config: preserve scope in do_git_config_sequence
  -:  ---------- >  8:  6c59c5cace config: teach git_config_source to remember its scope
  -:  ---------- >  9:  dd376246ec submodule-config: add subomdule config scope
  6:  fc141e8689 ! 10:  f76463ee90 config: add '--show-scope' to print the scope of a config value

@@ -12,7 +12,6 @@
parsing the '.gitmodules' file.

- Signed-off-by: Junio C Hamano <[email protected]>

diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt --- a/Documentation/git-config.txt
@@ -108,212 +107,6 @@
if (show_origin)
show_config_origin(buf);
if (show_keys)
-@@
- !strcmp(given_config_source.file, "-")) {
- given_config_source.file = NULL;
- given_config_source.use_stdin = 1;
-+ given_config_source.scope = CONFIG_SCOPE_COMMAND;
- }
-
- if (use_global_config) {
-@@
- */
- die(_("$HOME not set"));
-
-+ given_config_source.scope = CONFIG_SCOPE_GLOBAL;
-+
- if (access_or_warn(user_config, R_OK, 0) &&
- xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
- given_config_source.file = xdg_config;
-@@
- free(xdg_config);
- }
- }
-- else if (use_system_config)
-+ else if (use_system_config) {
- given_config_source.file = git_etc_gitconfig();
-- else if (use_local_config)
-+ given_config_source.scope = CONFIG_SCOPE_SYSTEM;
-+ } else if (use_local_config) {
- given_config_source.file = git_pathdup("config");
-- else if (use_worktree_config) {
-+ given_config_source.scope = CONFIG_SCOPE_LOCAL;
-+ } else if (use_worktree_config) {
- struct worktree **worktrees = get_worktrees(0);
- if (repository_format_worktree_config)
- given_config_source.file = git_pathdup("config.worktree");
-@@
- "section in \"git help worktree\" for details"));
- else
- given_config_source.file = git_pathdup("config");
-+ given_config_source.scope = CONFIG_SCOPE_LOCAL;
- free_worktrees(worktrees);
- } else if (given_config_source.file) {
- if (!is_absolute_path(given_config_source.file) && prefix)
- given_config_source.file =
- prefix_filename(prefix, given_config_source.file);
-+ given_config_source.scope = CONFIG_SCOPE_COMMAND;
-+ } else if (given_config_source.blob) {
-+ given_config_source.scope = CONFIG_SCOPE_COMMAND;
- }
-
-+
- if (respect_includes_opt == -1)
- config_options.respect_includes = !given_config_source.file;
- else
-
- diff --git a/config.c b/config.c
- --- a/config.c
- +++ b/config.c
-@@
- char *xdg_config = xdg_config_home("config");
- char *user_config = expand_user_path("~/.gitconfig", 0);
- char *repo_config;
-+ enum config_scope prev_parsing_scope = current_parsing_scope;
-
- if (opts->commondir)
- repo_config = mkpathdup("%s/config", opts->commondir);
-@@
- if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
- die(_("unable to parse command-line config"));
-
-- current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
-+ current_parsing_scope = prev_parsing_scope;
- free(xdg_config);
- free(user_config);
- free(repo_config);
-@@
- data = &inc;
- }
-
-+ if (config_source)
-+ current_parsing_scope = config_source->scope;
-+
- /*
- * If we have a specific filename, use it. Otherwise, follow the
- * regular lookup sequence.
-@@
- }
- }
-
-+const char *config_scope_name(enum config_scope scope)
-+{
-+ switch (scope) {
-+ case CONFIG_SCOPE_SYSTEM:
-+ return "system";
-+ case CONFIG_SCOPE_GLOBAL:
-+ return "global";
-+ case CONFIG_SCOPE_LOCAL:
-+ return "local";
-+ case CONFIG_SCOPE_WORKTREE:
-+ return "worktree";
-+ case CONFIG_SCOPE_COMMAND:
-+ return "command";
-+ case CONFIG_SCOPE_SUBMODULE:
-+ return "submodule";
-+ default:
-+ return "unknown";
-+ }
-+}
-+
- const char *current_config_name(void)
- {
- const char *name;
-
- diff --git a/config.h b/config.h
- --- a/config.h
- +++ b/config.h
-@@
-
- #define CONFIG_REGEX_NONE ((void *)1)
-
-+enum config_scope {
-+ CONFIG_SCOPE_UNKNOWN = 0,
-+ CONFIG_SCOPE_SYSTEM,
-+ CONFIG_SCOPE_GLOBAL,
-+ CONFIG_SCOPE_LOCAL,
-+ CONFIG_SCOPE_WORKTREE,
-+ CONFIG_SCOPE_COMMAND,
-+ CONFIG_SCOPE_SUBMODULE,
-+};
-+const char *config_scope_name(enum config_scope scope);
-+
- struct git_config_source {
- unsigned int use_stdin:1;
- const char *file;
- const char *blob;
-+ enum config_scope scope;
- };
-
- enum config_origin_type {
-@@
-
- int git_config_parse_parameter(const char *, config_fn_t fn, void *data); -
--enum config_scope {
-- CONFIG_SCOPE_UNKNOWN = 0,
-- CONFIG_SCOPE_SYSTEM,
-- CONFIG_SCOPE_GLOBAL,
-- CONFIG_SCOPE_LOCAL,
-- CONFIG_SCOPE_WORKTREE,
-- CONFIG_SCOPE_COMMAND,
--};
--
- enum config_scope current_config_scope(void);
- const char *current_config_origin_type(void);
- const char *current_config_name(void);
-
- diff --git a/submodule-config.c b/submodule-config.c
- --- a/submodule-config.c
- +++ b/submodule-config.c
-@@
- static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
- {
- if (repo->worktree) {
-- struct git_config_source config_source = { 0 };
-+ struct git_config_source config_source = {
-+ 0, .scope = CONFIG_SCOPE_SUBMODULE
-+ };
- const struct config_options opts = { 0 };
- struct object_id oid;
- char *file;
-
- diff --git a/t/helper/test-config.c b/t/helper/test-config.c
- --- a/t/helper/test-config.c
- +++ b/t/helper/test-config.c
-@@
- *
- */
-
--static const char *scope_name(enum config_scope scope)
--{
-- switch (scope) {
-- case CONFIG_SCOPE_SYSTEM:
-- return "system";
-- case CONFIG_SCOPE_GLOBAL:
-- return "global";
-- case CONFIG_SCOPE_LOCAL:
-- return "local";
-- case CONFIG_SCOPE_WORKTREE:
-- return "worktree";
-- case CONFIG_SCOPE_COMMAND:
-- return "command";
-- default:
-- return "unknown";
-- }
--}
- static int iterate_cb(const char *var, const char *value, void *data)
- {
- static int nr;
-@@
- printf("value=%s\n", value ? value : "(null)");
- printf("origin=%s\n", current_config_origin_type());
- printf("name=%s\n", current_config_name());
-- printf("scope=%s\n", scope_name(current_config_scope()));
-+ printf("scope=%s\n", config_scope_name(current_config_scope()));
-
- return 0;
- }

diff --git a/t/t1300-config.sh b/t/t1300-config.sh --- a/t/t1300-config.sh

Signature · 1 line
gitgitgadget
#79 lore raw

PATCH v7 3/10 t1300: create custom config file without special characters

From: Matthew Rogers <[email protected]>

Tests that required a custom configuration file to be created previously used a file with non-alphanumeric characters including escaped double quotes. This is not really necessary for the majority of tests involving custom config files, and decreases test coverage on systems that dissallow such filenames (Windows, etc.).

Create two files, one appropriate for testing quoting and one appropriate for general use.

---
 t/t1300-config.sh | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
t/t1300-config.sh +10 -5
index e8b4575758..e5fb9114f6 100755
@@ -1710,18 +1710,23 @@ test_expect_success '--show-origin getting a single key' '
 '
 
 test_expect_success 'set up custom config file' '
-	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
+	CUSTOM_CONFIG_FILE="custom.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
 	[user]
 		custom = true
 	EOF
 '
 
+test_expect_success !MINGW 'set up custom config file with special name characters' '
+	WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
+	cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
+'
+
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
 	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
-	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
+	git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
 	test_cmp expect output
 '
 
@@ -1747,7 +1752,7 @@ test_expect_success '--show-origin stdin with file include' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob' '
+test_expect_success '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
 	blob:$blob	user.custom=true
@@ -1756,9 +1761,9 @@ test_expect_success !MINGW '--show-origin blob' '
 	test_cmp expect output
 '
 
-test_expect_success !MINGW '--show-origin blob ref' '
+test_expect_success '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:master:custom.conf	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#78 lore raw

PATCH v7 2/10 t1300: fix over-indented HERE-DOCs

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Prepare for the following patches by removing extraneous indents from HERE-DOCs used in config tests.

---
 t/t1300-config.sh | 168 +++++++++++++++++++++++-----------------------
 1 file changed, 84 insertions(+), 84 deletions(-)
t/t1300-config.sh +84 -84
index 983a0a1583..e8b4575758 100755
@@ -1191,47 +1191,47 @@ test_expect_success 'old-fashioned settings are case insensitive' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		Qr = value2
+	[V.A]
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.a.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		QR = value2
+	[V.A]
+	QR = value2
 	EOF
 	git config -f testConfig_actual "V.a.R" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "V.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V.A]
-		r = value1
+	[V.A]
+	r = value1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V.A]
-		r = value1
-		Qr = value2
+	[V.A]
+	r = value1
+	Qr = value2
 	EOF
 	git config -f testConfig_actual "v.A.r" value2 &&
 	test_cmp testConfig_expect testConfig_actual
@@ -1241,26 +1241,26 @@ test_expect_success 'setting different case sensitive subsections ' '
 	test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
 
 	cat >testConfig_actual <<-EOF &&
-		[V "A"]
-		R = v1
-		[K "E"]
-		Y = v1
-		[a "b"]
-		c = v1
-		[d "e"]
-		f = v1
+	[V "A"]
+	R = v1
+	[K "E"]
+	Y = v1
+	[a "b"]
+	c = v1
+	[d "e"]
+	f = v1
 	EOF
 	q_to_tab >testConfig_expect <<-EOF &&
-		[V "A"]
-		Qr = v2
-		[K "E"]
-		Qy = v2
-		[a "b"]
-		Qc = v2
-		[d "e"]
-		f = v1
-		[d "E"]
-		Qf = v2
+	[V "A"]
+	Qr = v2
+	[K "E"]
+	Qy = v2
+	[a "b"]
+	Qc = v2
+	[d "e"]
+	f = v1
+	[d "E"]
+	Qf = v2
 	EOF
 	# exact match
 	git config -f testConfig_actual a.b.c v2 &&
@@ -1622,40 +1622,40 @@ test_expect_success 'set up --show-origin tests' '
 	INCLUDE_DIR="$HOME/include" &&
 	mkdir -p "$INCLUDE_DIR" &&
 	cat >"$INCLUDE_DIR"/absolute.include <<-\EOF &&
-		[user]
-			absolute = include
+	[user]
+		absolute = include
 	EOF
 	cat >"$INCLUDE_DIR"/relative.include <<-\EOF &&
-		[user]
-			relative = include
+	[user]
+		relative = include
 	EOF
 	cat >"$HOME"/.gitconfig <<-EOF &&
-		[user]
-			global = true
-			override = global
-		[include]
-			path = "$INCLUDE_DIR/absolute.include"
+	[user]
+		global = true
+		override = global
+	[include]
+		path = "$INCLUDE_DIR/absolute.include"
 	EOF
 	cat >.git/config <<-\EOF
-		[user]
-			local = true
-			override = local
-		[include]
-			path = ../include/relative.include
+	[user]
+		local = true
+		override = local
+	[include]
+		path = ../include/relative.include
 	EOF
 '
 
 test_expect_success '--show-origin with --list' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global=true
-		file:$HOME/.gitconfig	user.override=global
-		file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
-		file:$INCLUDE_DIR/absolute.include	user.absolute=include
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
-		file:.git/../include/relative.include	user.relative=include
-		command line:	user.cmdline=true
+	file:$HOME/.gitconfig	user.global=true
+	file:$HOME/.gitconfig	user.override=global
+	file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+	file:$INCLUDE_DIR/absolute.include	user.absolute=include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
+	file:.git/../include/relative.include	user.relative=include
+	command line:	user.cmdline=true
 	EOF
 	git -c user.cmdline=true config --list --show-origin >output &&
 	test_cmp expect output
@@ -1663,16 +1663,16 @@ test_expect_success '--show-origin with --list' '
 
 test_expect_success '--show-origin with --list --null' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfigQuser.global
-		trueQfile:$HOME/.gitconfigQuser.override
-		globalQfile:$HOME/.gitconfigQinclude.path
-		$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
-		includeQfile:.git/configQuser.local
-		trueQfile:.git/configQuser.override
-		localQfile:.git/configQinclude.path
-		../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
-		includeQcommand line:Quser.cmdline
-		trueQ
+	file:$HOME/.gitconfigQuser.global
+	trueQfile:$HOME/.gitconfigQuser.override
+	globalQfile:$HOME/.gitconfigQinclude.path
+	$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
+	includeQfile:.git/configQuser.local
+	trueQfile:.git/configQuser.override
+	localQfile:.git/configQinclude.path
+	../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
+	includeQcommand line:Quser.cmdline
+	trueQ
 	EOF
 	git -c user.cmdline=true config --null --list --show-origin >output.raw &&
 	nul_to_q <output.raw >output &&
@@ -1684,9 +1684,9 @@ test_expect_success '--show-origin with --list --null' '
 
 test_expect_success '--show-origin with single file' '
 	cat >expect <<-\EOF &&
-		file:.git/config	user.local=true
-		file:.git/config	user.override=local
-		file:.git/config	include.path=../include/relative.include
+	file:.git/config	user.local=true
+	file:.git/config	user.override=local
+	file:.git/config	include.path=../include/relative.include
 	EOF
 	git config --local --list --show-origin >output &&
 	test_cmp expect output
@@ -1694,8 +1694,8 @@ test_expect_success '--show-origin with single file' '
 
 test_expect_success '--show-origin with --get-regexp' '
 	cat >expect <<-EOF &&
-		file:$HOME/.gitconfig	user.global true
-		file:.git/config	user.local true
+	file:$HOME/.gitconfig	user.global true
+	file:.git/config	user.local true
 	EOF
 	git config --show-origin --get-regexp "user\.[g|l].*" >output &&
 	test_cmp expect output
@@ -1703,7 +1703,7 @@ test_expect_success '--show-origin with --get-regexp' '
 
 test_expect_success '--show-origin getting a single key' '
 	cat >expect <<-\EOF &&
-		file:.git/config	local
+	file:.git/config	local
 	EOF
 	git config --show-origin user.override >output &&
 	test_cmp expect output
@@ -1712,14 +1712,14 @@ test_expect_success '--show-origin getting a single key' '
 test_expect_success 'set up custom config file' '
 	CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" &&
 	cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
-		[user]
-			custom = true
+	[user]
+		custom = true
 	EOF
 '
 
 test_expect_success !MINGW '--show-origin escape special file name characters' '
 	cat >expect <<-\EOF &&
-		file:"file\" (dq) and spaces.conf"	user.custom=true
+	file:"file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
 	test_cmp expect output
@@ -1727,7 +1727,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' '
 
 test_expect_success '--show-origin stdin' '
 	cat >expect <<-\EOF &&
-		standard input:	user.custom=true
+	standard input:	user.custom=true
 	EOF
 	git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
 	test_cmp expect output
@@ -1735,11 +1735,11 @@ test_expect_success '--show-origin stdin' '
 
 test_expect_success '--show-origin stdin with file include' '
 	cat >"$INCLUDE_DIR"/stdin.include <<-EOF &&
-		[user]
-			stdin = include
+	[user]
+		stdin = include
 	EOF
 	cat >expect <<-EOF &&
-		file:$INCLUDE_DIR/stdin.include	include
+	file:$INCLUDE_DIR/stdin.include	include
 	EOF
 	echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
 	git config --show-origin --includes --file - user.stdin >output &&
@@ -1750,7 +1750,7 @@ test_expect_success '--show-origin stdin with file include' '
 test_expect_success !MINGW '--show-origin blob' '
 	blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
 	cat >expect <<-EOF &&
-		blob:$blob	user.custom=true
+	blob:$blob	user.custom=true
 	EOF
 	git config --blob=$blob --show-origin --list >output &&
 	test_cmp expect output
@@ -1758,7 +1758,7 @@ test_expect_success !MINGW '--show-origin blob' '
 
 test_expect_success !MINGW '--show-origin blob ref' '
 	cat >expect <<-\EOF &&
-		blob:"master:file\" (dq) and spaces.conf"	user.custom=true
+	blob:"master:file\" (dq) and spaces.conf"	user.custom=true
 	EOF
 	git add "$CUSTOM_CONFIG_FILE" &&
 	git commit -m "new config file" &&
Signature · 1 line
gitgitgadget
#87 lore raw

PATCH v7 5/10 config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

---
 config.c              | 13 ++++++-------
 config.h              |  3 ++-
 remote.c              |  3 ++-
 t/t1308-config-set.sh |  2 +-
 upload-pack.c         |  3 ++-
 5 files changed, 13 insertions(+), 11 deletions(-)
config.c +6 -7
index 83bb98d65e..7422bdebb1 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
@@ -3304,8 +3301,10 @@ const char *config_scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "command line";
 	default:
config.h +2 -1
index dcb8c274d4..d3ed41ef8e 100644
@@ -299,7 +299,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 const char *config_scope_name(enum config_scope scope);
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/t1308-config-set.sh +1 -1
index 5f3e71a160..728a2b87ce 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
Signature · 1 line
gitgitgadget
#89 lore raw

PATCH v7 6/10 config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

---
 config.c              | 6 +++---
 config.h              | 2 +-
 t/t1308-config-set.sh | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
config.c +3 -3
index 7422bdebb1..fe1e44a43a 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
@@ -3305,8 +3305,8 @@ const char *config_scope_name(enum config_scope scope)
 		return "local";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "command line";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
config.h +1 -1
index d3ed41ef8e..b570f4ce43 100644
@@ -301,7 +301,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 const char *config_scope_name(enum config_scope scope);
 
t/t1308-config-set.sh +1 -1
index 728a2b87ce..fba0abe429 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=command line
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
Signature · 1 line
gitgitgadget
#91 lore raw

PATCH v7 7/10 config: preserve scope in do_git_config_sequence

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

do_git_config_sequence operated under the assumption that it was correct to set current_parsing_scope to CONFIG_SCOPE_UNKNOWN as part of the cleanup it does after it finishes execution. This is incorrect, as it blows away the current_parsing_scope if do_git_config_sequence is called recursively. As such situations are rare (git config running with the '--blob' option is one example) this has yet to cause a problem, but the upcoming '--show-scope' option will experience issues in that case, lets teach do_git_config_sequence to preserve the current_parsing_scope from before it started execution.

---
 config.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
config.c +2 -1
index fe1e44a43a..0e2c693e78 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
Signature · 1 line
gitgitgadget
#95 lore raw

PATCH v7 9/10 submodule-config: add subomdule config scope

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Before the changes to teach git_config_source to remember scope information submodule-config.c never needed to consider the question of config scope. Even though zeroing out git_config_source is still correct and preserved the previous behavior of setting the scope to CONFIG_SCOPE_UNKNOWN, it's better to be explicit about such situations by explicitly setting the scope. As none of the current config_scope enumerations make sense we create CONFIG_SCOPE_SUBMODULE to describe the situation.

---
 config.c           | 2 ++
 config.h           | 1 +
 submodule-config.c | 4 +++-
 3 files changed, 6 insertions(+), 1 deletion(-)
config.c +2 -0
index 9b6afca210..18a6bdd9ff 100644
@@ -3311,6 +3311,8 @@ const char *config_scope_name(enum config_scope scope)
 		return "worktree";
 	case CONFIG_SCOPE_COMMAND:
 		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
 	default:
 		return "unknown";
 	}
config.h +1 -0
index 165cacb7da..fe0addb0dc 100644
@@ -42,6 +42,7 @@ enum config_scope {
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
 };
 const char *config_scope_name(enum config_scope scope);
 
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
Signature · 1 line
gitgitgadget
#97 lore raw

PATCH v7 10/10 config: add '--show-scope' to print the scope of a config value

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

When a user queries config values with --show-origin, often it's difficult to determine what the actual "scope" (local, global, etc.) of a given value is based on just the origin file.

Teach 'git config' the '--show-scope' option to print the scope of all displayed config values. Note that we should never see anything of "submodule" scope as that is only ever used by submodule-config.c when parsing the '.gitmodules' file.

---
 Documentation/git-config.txt | 15 ++++++---
 builtin/config.c             | 20 ++++++++++--
 t/t1300-config.sh            | 59 ++++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+), 7 deletions(-)
Documentation/git-config.txt +10 -5
index 899e92a1c9..7573160f21 100644
@@ -9,18 +9,18 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [--type=<type>] --add name value
 'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
+'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -222,6 +222,11 @@ Valid `<type>`'s include:
 	the actual origin (config file path, ref, or blob id if
 	applicable).
 
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value
+	(local, global, system, command).
+
 --get-colorbool name [stdout-is-tty]::
 
 	Find the color setting for `name` (e.g. `color.diff`) and output
builtin/config.c +18 -2
index 0a9778b714..ee4aef6a35 100644
@@ -33,6 +33,7 @@ static int end_nul;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
 static int show_origin;
+static int show_scope;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -155,6 +156,7 @@ static struct option builtin_config_options[] = {
 	OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
 	OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
 	OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+	OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
 	OPT_END(),
 };
@@ -189,11 +191,23 @@ static void show_config_origin(struct strbuf *buf)
 	strbuf_addch(buf, term);
 }
 
+static void show_config_scope(struct strbuf *buf)
+{
+	const char term = end_nul ? '\0' : '\t';
+	const char *scope = config_scope_name(current_config_scope());
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-	if (show_origin) {
+	if (show_origin || show_scope) {
 		struct strbuf buf = STRBUF_INIT;
-		show_config_origin(&buf);
+		if (show_scope)
+			show_config_scope(&buf);
+		if (show_origin)
+			show_config_origin(&buf);
 		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
 		fwrite(buf.buf, 1, buf.len, stdout);
 		strbuf_release(&buf);
@@ -213,6 +227,8 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
+	if (show_scope)
+		show_config_scope(buf);
 	if (show_origin)
 		show_config_origin(buf);
 	if (show_keys)
t/t1300-config.sh +59 -0

65 lines not on this page · raw message

Signature · 1 line
gitgitgadget
#93 lore raw

PATCH v7 8/10 config: teach git_config_source to remember its scope

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

There are many situations where the scope of a config command is known beforehand, such as passing of '--local', '--file', etc. to an invocation of git config. However, this information is lost when moving from builtin/config.c to /config.c. This historically hasn't been a big deal, but to prepare for the upcoming --show-scope option we teach git_config_source to keep track of the source and the config machinery to use that information to set current_parsing_scope appropriately.

---
 builtin/config.c | 16 +++++++++++++---
 config.c         |  3 +++
 config.h         | 20 ++++++++++----------
 3 files changed, 26 insertions(+), 13 deletions(-)
builtin/config.c +13 -3
index 52a904cfb1..0a9778b714 100644
@@ -622,6 +622,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
 		given_config_source.use_stdin = 1;
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
 	if (use_global_config) {
@@ -637,6 +638,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			 */
 			die(_("$HOME not set"));
 
+		given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
 		if (access_or_warn(user_config, R_OK, 0) &&
 		    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
 			given_config_source.file = xdg_config;
@@ -646,11 +649,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			free(xdg_config);
 		}
 	}
-	else if (use_system_config)
+	else if (use_system_config) {
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+		given_config_source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (use_local_config) {
 		given_config_source.file = git_pathdup("config");
-	else if (use_worktree_config) {
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (use_worktree_config) {
 		struct worktree **worktrees = get_worktrees(0);
 		if (repository_format_worktree_config)
 			given_config_source.file = git_pathdup("config.worktree");
@@ -662,13 +667,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			      "section in \"git help worktree\" for details"));
 		else
 			given_config_source.file = git_pathdup("config");
+		given_config_source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				prefix_filename(prefix, given_config_source.file);
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (given_config_source.blob) {
+		given_config_source.scope = CONFIG_SCOPE_COMMAND;
 	}
 
+
 	if (respect_includes_opt == -1)
 		config_options.respect_includes = !given_config_source.file;
 	else
config.c +3 -0
index 0e2c693e78..9b6afca210 100644
@@ -1763,6 +1763,9 @@ int config_with_options(config_fn_t fn, void *data,
 		data = &inc;
 	}
 
+	if (config_source)
+		current_parsing_scope = config_source->scope;
+
 	/*
 	 * If we have a specific filename, use it. Otherwise, follow the
 	 * regular lookup sequence.
config.h +10 -10
index b570f4ce43..165cacb7da 100644
@@ -35,11 +35,21 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+enum config_scope {
+	CONFIG_SCOPE_UNKNOWN = 0,
+	CONFIG_SCOPE_SYSTEM,
+	CONFIG_SCOPE_GLOBAL,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
+	CONFIG_SCOPE_COMMAND,
+};
+const char *config_scope_name(enum config_scope scope);
 
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
 	const char *blob;
+	enum config_scope scope;
 };
 
 enum config_origin_type {
@@ -295,16 +305,6 @@ int config_error_nonbool(const char *);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope {
-	CONFIG_SCOPE_UNKNOWN = 0,
-	CONFIG_SCOPE_SYSTEM,
-	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_LOCAL,
-	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_COMMAND,
-};
-const char *config_scope_name(enum config_scope scope);
-
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
Signature · 1 line
gitgitgadget
#80 lore raw

PATCH v7 4/10 config: make scope_name non-static and rename it

In reply to Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

To prepare for the upcoming --show-scope option, we require the ability to convert a config_scope enum to a string. As this was originally implemented as a static function 'scope_name()' in t/helper/test-config.c, we expose it via config.h and give it a less ambiguous name 'config_scope_name()'

---
 config.c               | 16 ++++++++++++++++
 config.h               |  2 ++
 t/helper/test-config.c | 17 +----------------
 t/t1308-config-set.sh  |  2 +-
 4 files changed, 20 insertions(+), 17 deletions(-)
config.c +16 -0
index d75f88ca0c..83bb98d65e 100644
@@ -3297,6 +3297,22 @@ const char *current_config_origin_type(void)
 	}
 }
 
+const char *config_scope_name(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_REPO:
+		return "repo";
+	case CONFIG_SCOPE_CMDLINE:
+		return "command line";
+	default:
+		return "unknown";
+	}
+}
+
 const char *current_config_name(void)
 {
 	const char *name;
config.h +2 -0
index 91fd4c5e96..dcb8c274d4 100644
@@ -35,6 +35,7 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
@@ -301,6 +302,7 @@ enum config_scope {
 	CONFIG_SCOPE_REPO,
 	CONFIG_SCOPE_CMDLINE,
 };
+const char *config_scope_name(enum config_scope scope);
 
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
t/helper/test-config.c +1 -16
index 214003d5b2..1e3bc7c8f4 100644
@@ -37,21 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -63,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
 	return 0;
 }
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..5f3e71a160 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command line
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
Signature · 1 line
gitgitgadget
#81 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

Quoted 26 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

To prepare for the upcoming --show-scope option, we require the ability to convert a config_scope enum to a string. As this was originally implemented as a static function 'scope_name()' in t/helper/test-config.c, we expose it via config.h and give it a less ambiguous name 'config_scope_name()'

---
 config.c               | 16 ++++++++++++++++
 config.h               |  2 ++
 t/helper/test-config.c | 17 +----------------
 t/t1308-config-set.sh  |  2 +-
 4 files changed, 20 insertions(+), 17 deletions(-)
config.c +1 -0
index d75f88ca0c..83bb98d65e 100644
@@ -3297,6 +3297,22 @@ const char *current_config_origin_type(void)
 	}
 }
 
+const char *config_scope_name(enum config_scope scope)

config.c const char *current_config_origin_type(void) · line 3310

Quoted 10 lines
config.c +10 -0
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_REPO:
+		return "repo";
+	case CONFIG_SCOPE_CMDLINE:
+		return "command line";

The change from "cmdline" to "command line" does need to happen before the end of the series, but I do not think it should happen here, especialy given that the proposed log message explains that this step is to expose scope_name() under a better name (which is a very good split point).

How are you reviewing the patches in your own series before sending them out? This round is better than the previous rounds where we didn't have a matching change to the tests so "make test" may not have passed in the middle of the series, though...

Quoted 76 lines
config.c +5 -0
+	default:
+		return "unknown";
+	}
+}
+
 const char *current_config_name(void)
 {
 	const char *name;
config.h +2 -0
index 91fd4c5e96..dcb8c274d4 100644
@@ -35,6 +35,7 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
+
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
@@ -301,6 +302,7 @@ enum config_scope {
 	CONFIG_SCOPE_REPO,
 	CONFIG_SCOPE_CMDLINE,
 };
+const char *config_scope_name(enum config_scope scope);
 
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
t/helper/test-config.c +1 -16
index 214003d5b2..1e3bc7c8f4 100644
@@ -37,21 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -63,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
 	return 0;
 }
t/t1308-config-set.sh +1 -1
index 7b4e1a63eb..5f3e71a160 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=cmdline
+	scope=command line
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
#88 lore raw

Re: [PATCH v7 05/10] config: split repo scope to local and worktree

In reply to Matthew Rogers via GitGitGadget
Quoted 23 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Previously when iterating through git config variables, worktree config and local config were both considered "CONFIG_SCOPE_REPO". This was never a problem before as no one had needed to differentiate between the two cases, but future functionality may care whether or not the config options come from a worktree or from the repository's actual local config file. For example, the planned feature to add a '--show-scope' to config to allow a user to see which scope listed config options come from would confuse users if it just printed 'repo' rather than 'local' or 'worktree' as the documentation would lead them to expect. As well as the additional benefit of making the implementation look more like how the documentation describes the interface.

To accomplish this we split out what was previously considered repo scope to be local and worktree.

The clients of 'current_config_scope()' who cared about CONFIG_SCOPE_REPO are also modified to similarly care about CONFIG_SCOPE_WORKTREE and CONFIG_SCOPE_LOCAL to preserve previous behavior.

Quoted 7 lines
---
 config.c              | 13 ++++++-------
 config.h              |  3 ++-
 remote.c              |  3 ++-
 t/t1308-config-set.sh |  2 +-
 upload-pack.c         |  3 ++-
 5 files changed, 13 insertions(+), 11 deletions(-)

Makes sense. And this step does exactly what it claims to do and nothing else, which is very good ;-)

Quoted 90 lines
config.c +6 -7
index 83bb98d65e..7422bdebb1 100644
@@ -1724,15 +1724,12 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
 		ret += git_config_from_file(fn, user_config, data);
 
-	current_parsing_scope = CONFIG_SCOPE_REPO;
+	current_parsing_scope = CONFIG_SCOPE_LOCAL;
 	if (!opts->ignore_repo && repo_config &&
 	    !access_or_die(repo_config, R_OK, 0))
 		ret += git_config_from_file(fn, repo_config, data);
 
-	/*
-	 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE.
-	 * But let's not complicate things before it's actually needed.
-	 */
+	current_parsing_scope = CONFIG_SCOPE_WORKTREE;
 	if (!opts->ignore_worktree && repository_format_worktree_config) {
 		char *path = git_pathdup("config.worktree");
 		if (!access_or_die(path, R_OK, 0))
@@ -3304,8 +3301,10 @@ const char *config_scope_name(enum config_scope scope)
 		return "system";
 	case CONFIG_SCOPE_GLOBAL:
 		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
+	case CONFIG_SCOPE_LOCAL:
+		return "local";
+	case CONFIG_SCOPE_WORKTREE:
+		return "worktree";
 	case CONFIG_SCOPE_CMDLINE:
 		return "command line";
 	default:
config.h +2 -1
index dcb8c274d4..d3ed41ef8e 100644
@@ -299,7 +299,8 @@ enum config_scope {
 	CONFIG_SCOPE_UNKNOWN = 0,
 	CONFIG_SCOPE_SYSTEM,
 	CONFIG_SCOPE_GLOBAL,
-	CONFIG_SCOPE_REPO,
+	CONFIG_SCOPE_LOCAL,
+	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_CMDLINE,
 };
 const char *config_scope_name(enum config_scope scope);
remote.c +2 -1
index 5c4666b53a..593ce297ed 100644
@@ -369,7 +369,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 	}
 	remote = make_remote(name, namelen);
 	remote->origin = REMOTE_CONFIG;
-	if (current_config_scope() == CONFIG_SCOPE_REPO)
+	if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+	current_config_scope() == CONFIG_SCOPE_WORKTREE)
 		remote->configured_in_repo = 1;
 	if (!strcmp(subkey, "mirror"))
 		remote->mirror = git_config_bool(key, value);
t/t1308-config-set.sh +1 -1
index 5f3e71a160..728a2b87ce 100755
@@ -259,7 +259,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-repo
 	origin=file
 	name=.git/config
-	scope=repo
+	scope=local
 
 	key=foo.bar
 	value=from-cmdline
upload-pack.c +2 -1
index a00d7ece6b..c53249cac1 100644
@@ -1073,7 +1073,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		precomposed_unicode = git_config_bool(var, value);
 	}
 
-	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+	if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
+	current_config_scope() != CONFIG_SCOPE_WORKTREE) {
 		if (!strcmp("uploadpack.packobjectshook", var))
 			return git_config_string(&pack_objects_hook, var, value);
 	}
#90 lore raw

Re: [PATCH v7 06/10] config: clarify meaning of command line scoping

In reply to Matthew Rogers via GitGitGadget
Quoted 11 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

CONFIG_SCOPE_CMDLINE is generally used in the code to refer to config values passed in via the -c option. Options passed in using this mechanism share similar scoping characteristics with the --file and --blob options of the 'config' command, namely that they are only in use for that single invocation of git, and that they supersede the normal system/global/local hierarchy. This patch introduces CONFIG_SCOPE_COMMAND to reflect this new idea, which also makes CONFIG_SCOPE_CMDLINE redundant.

Quoted 7 lines
---
 config.c              | 6 +++---
 config.h              | 2 +-
 t/t1308-config-set.sh | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

This makes sense, even though it is halfway undoing what 04/10 unnecessarily did ;-)

I think I can just wiggle minor fixes in to 04/10 and then adjust this one to get the series into a better shape myself before queuing them to expedite the process. Let me finish reading the remainder of the topic.

Thanks.

Quoted 50 lines
config.c +3 -3
index 7422bdebb1..fe1e44a43a 100644
@@ -1737,7 +1737,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 		free(path);
 	}
 
-	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
+	current_parsing_scope = CONFIG_SCOPE_COMMAND;
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
@@ -3305,8 +3305,8 @@ const char *config_scope_name(enum config_scope scope)
 		return "local";
 	case CONFIG_SCOPE_WORKTREE:
 		return "worktree";
-	case CONFIG_SCOPE_CMDLINE:
-		return "command line";
+	case CONFIG_SCOPE_COMMAND:
+		return "command";
 	default:
 		return "unknown";
 	}
config.h +1 -1
index d3ed41ef8e..b570f4ce43 100644
@@ -301,7 +301,7 @@ enum config_scope {
 	CONFIG_SCOPE_GLOBAL,
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
-	CONFIG_SCOPE_CMDLINE,
+	CONFIG_SCOPE_COMMAND,
 };
 const char *config_scope_name(enum config_scope scope);
 
t/t1308-config-set.sh +1 -1
index 728a2b87ce..fba0abe429 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=command line
+	scope=command
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
#92 lore raw

Re: [PATCH v7 07/10] config: preserve scope in do_git_config_sequence

In reply to Matthew Rogers via GitGitGadget
Quoted 12 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

do_git_config_sequence operated under the assumption that it was correct to set current_parsing_scope to CONFIG_SCOPE_UNKNOWN as part of the cleanup it does after it finishes execution. This is incorrect, as it blows away the current_parsing_scope if do_git_config_sequence is called recursively. As such situations are rare (git config running with the '--blob' option is one example) this has yet to cause a problem, but the upcoming '--show-scope' option will experience issues in that case, lets teach do_git_config_sequence to preserve the current_parsing_scope from before it started execution.

Quoted 4 lines
---
 config.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

This step is new and it does make sense.

Thanks.

Quoted 21 lines
config.c +2 -1
index fe1e44a43a..0e2c693e78 100644
@@ -1702,6 +1702,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	char *xdg_config = xdg_config_home("config");
 	char *user_config = expand_user_path("~/.gitconfig", 0);
 	char *repo_config;
+	enum config_scope prev_parsing_scope = current_parsing_scope;
 
 	if (opts->commondir)
 		repo_config = mkpathdup("%s/config", opts->commondir);
@@ -1741,7 +1742,7 @@ static int do_git_config_sequence(const struct config_options *opts,
 	if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
 		die(_("unable to parse command-line config"));
 
-	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
+	current_parsing_scope = prev_parsing_scope;
 	free(xdg_config);
 	free(user_config);
 	free(repo_config);
#94 lore raw

Re: [PATCH v7 08/10] config: teach git_config_source to remember its scope

In reply to Matthew Rogers via GitGitGadget
Quoted 10 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

There are many situations where the scope of a config command is known beforehand, such as passing of '--local', '--file', etc. to an invocation of git config. However, this information is lost when moving from builtin/config.c to /config.c. This historically hasn't been a big deal, but to prepare for the upcoming --show-scope option we teach git_config_source to keep track of the source and the config machinery to use that information to set current_parsing_scope appropriately.

Quoted 6 lines
---
 builtin/config.c | 16 +++++++++++++---
 config.c         |  3 +++
 config.h         | 20 ++++++++++----------
 3 files changed, 26 insertions(+), 13 deletions(-)

This is split from the last step in the previous round, and the splitting makes sense.

Thanks.

#96 lore raw

Re: [PATCH v7 09/10] submodule-config: add subomdule config scope

In reply to Matthew Rogers via GitGitGadget
Quoted 11 lines · Matthew Rogers via GitGitGadget

From: Matthew Rogers <[email protected]>

Before the changes to teach git_config_source to remember scope information submodule-config.c never needed to consider the question of config scope. Even though zeroing out git_config_source is still correct and preserved the previous behavior of setting the scope to CONFIG_SCOPE_UNKNOWN, it's better to be explicit about such situations by explicitly setting the scope. As none of the current config_scope enumerations make sense we create CONFIG_SCOPE_SUBMODULE to describe the situation.

Quoted 2 lines

---

Other than a typo on the title, I think this one is perfect ;-)

Will queue.

Quoted 45 lines
 config.c           | 2 ++
 config.h           | 1 +
 submodule-config.c | 4 +++-
 3 files changed, 6 insertions(+), 1 deletion(-)
config.c +2 -0
index 9b6afca210..18a6bdd9ff 100644
@@ -3311,6 +3311,8 @@ const char *config_scope_name(enum config_scope scope)
 		return "worktree";
 	case CONFIG_SCOPE_COMMAND:
 		return "command";
+	case CONFIG_SCOPE_SUBMODULE:
+		return "submodule";
 	default:
 		return "unknown";
 	}
config.h +1 -0
index 165cacb7da..fe0addb0dc 100644
@@ -42,6 +42,7 @@ enum config_scope {
 	CONFIG_SCOPE_LOCAL,
 	CONFIG_SCOPE_WORKTREE,
 	CONFIG_SCOPE_COMMAND,
+	CONFIG_SCOPE_SUBMODULE,
 };
 const char *config_scope_name(enum config_scope scope);
 
submodule-config.c +3 -1
index 85064810b2..b8e97d8ae8 100644
@@ -635,7 +635,9 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		struct git_config_source config_source = { 0 };
+		struct git_config_source config_source = {
+			0, .scope = CONFIG_SCOPE_SUBMODULE
+		};
 		const struct config_options opts = { 0 };
 		struct object_id oid;
 		char *file;
#82 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

In reply to Junio C Hamano
Quoted 5 lines · Junio C Hamano

The change from "cmdline" to "command line" does need to happen before the end of the series, but I do not think it should happen here, especialy given that the proposed log message explains that this step is to expose scope_name() under a better name (which is a very good split point).

I'll tweak this step with the attached patch, and then adjust 06/10 as needed, while queuing.

 config.c              | 2 +-
 config.h              | 1 -
 t/t1308-config-set.sh | 2 +-
 3 files changed, 2 insertions(+), 3 deletions(-)
config.c +1 -1
index 83bb98d65e..a922b136e5 100644
@@ -3307,7 +3307,7 @@ const char *config_scope_name(enum config_scope scope)
 	case CONFIG_SCOPE_REPO:
 		return "repo";
 	case CONFIG_SCOPE_CMDLINE:
-		return "command line";
+		return "cmdline";
 	default:
 		return "unknown";
 	}
config.h +0 -1
index dcb8c274d4..c063f33ff6 100644
@@ -35,7 +35,6 @@ struct object_id;
 
 #define CONFIG_REGEX_NONE ((void *)1)
 
-
 struct git_config_source {
 	unsigned int use_stdin:1;
 	const char *file;
t/t1308-config-set.sh +1 -1
index 5f3e71a160..7b4e1a63eb 100755
@@ -265,7 +265,7 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-cmdline
 	origin=command line
 	name=
-	scope=command line
+	scope=cmdline
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
 	test_cmp expect actual
#83 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

In reply to Junio C Hamano
Quoted 6 lines

How are you reviewing the patches in your own series before sending them out? This round is better than the previous rounds where we didn't have a matching change to the tests so "make test" may not have passed in the middle of the series, though...

I went through each patch individually using rebase -i and built/tested it. Although just to save time I only did t1300 and t1308 since I believe those were the only ones that should be affected. I can write a script that would run the whole
test suite overnight for me and make sure the series shakes out okay, if you'd like.

#84 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

Quoted 7 lines · Matt Rogers
Quoted 6 lines

How are you reviewing the patches in your own series before sending them out? This round is better than the previous rounds where we didn't have a matching change to the tests so "make test" may not have passed in the middle of the series, though...

Quoted 6 lines

I went through each patch individually using rebase -i and built/tested it. Although just to save time I only did t1300 and t1308 since I believe those were the only ones that should be affected. I can write a script that would run the whole
test suite overnight for me and make sure the series shakes out okay, if you'd like.

Not sure whether you intend to do this or not, but to maybe save you some scripting, I do this like so:

  git rebase -x \
    "make -j16 && (cd t && prove -j16 -v --shuffle t[0-9]*.sh)" master

If the tests fail, the rebase is paused, which can be understandably disappointing if you walk away from it overnight only to have it fail after 10 minutes, though. :)

- Emily

#85 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

In reply to Matt Rogers
Quoted 6 lines · Matt Rogers
Quoted 5 lines

How are you reviewing the patches in your own series before sending them out? This round is better than the previous rounds where we didn't have a matching change to the tests so "make test" may not have passed in the middle of the series, though...

Quoted 6 lines

I went through each patch individually using rebase -i and built/tested it. Although just to save time I only did t1300 and t1308 since I believe those were the only ones that should be affected. I can write a script that would run the whole
test suite overnight for me and make sure the series shakes out okay, if you'd like.

What I like does not matter.

What I pointed out for 04/10 wouldn't have been caught by your testing anyway, as both the code and the test had matching unnecessry changes. I was wondering if you are relying too heavily on just tests and without actually proofreading the changes to see if they still make sense in the context of the updated series, and if my suspicion was correct, if there are something reviewers can do to help the authors.

#86 lore raw

Re: [PATCH v7 04/10] config: make scope_name non-static and rename it

Quoted 18 lines · Junio C Hamano
Quoted 6 lines · Matt Rogers
Quoted 5 lines

How are you reviewing the patches in your own series before sending them out? This round is better than the previous rounds where we didn't have a matching change to the tests so "make test" may not have passed in the middle of the series, though...

Quoted 6 lines

I went through each patch individually using rebase -i and built/tested it. Although just to save time I only did t1300 and t1308 since I believe those were the only ones that should be affected. I can write a script that would run the whole
test suite overnight for me and make sure the series shakes out okay, if you'd like.

What I like does not matter.

Quoted 9 lines

What I pointed out for 04/10 wouldn't have been caught by your testing anyway, as both the code and the test had matching unnecessry changes. I was wondering if you are relying too heavily on just tests and without actually proofreading the changes to see if they still make sense in the context of the updated series, and if my suspicion was correct, if there are something reviewers can do to help the authors.

I do try to proofread patches, I'm just not the most careful of reviewers at times, partially as a personal problem and partially as this is a new workflow for me. As for the particular issue, I just thought it was a good idea at the time and I didn't think it all the way through

Signature · 1 line
Matthew Rogers