git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 07/11] config: extract location structs from builtin

From
Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Date
Feb 4, 2026, 14:19 UTC
Message-ID
<4be089a4dda63fdc0ea2db00acb47b33befe07ef.1770214803.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.2033.git.1770214803.gitgitgadget@gmail.com>
From: Derrick Stolee <stolee@gmail.com>

Before reusing these concepts in builtin/config-batch.c, extract the config_location_options struct from builtin/config.c to config.h with implementation in config.c.

The only modification in this conversion is the use of a repository parameter instead of the_repository.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
 builtin/config.c | 117 ++++-------------------------------------------
 config.c         |  89 +++++++++++++++++++++++++++++++++++
 config.h         |  20 ++++++++
 3 files changed, 117 insertions(+), 109 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 288ebdfdaa..d129b1204d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -71,20 +71,6 @@ static const char *const builtin_config_edit_usage[] = {
 	OPT_STRING('f', "file", &opts.source.file, N_("file"), N_("use given config file")), \
 	OPT_STRING(0, "blob", &opts.source.blob, N_("blob-id"), N_("read config from given blob object"))
 
-struct config_location_options {
-	struct git_config_source source;
-	struct config_options options;
-	char *file_to_free;
-	int use_global_config;
-	int use_system_config;
-	int use_local_config;
-	int use_worktree_config;
-	int respect_includes_opt;
-};
-#define CONFIG_LOCATION_OPTIONS_INIT { \
-	.respect_includes_opt = -1, \
-}
-
 #define CONFIG_TYPE_OPTIONS(type) \
 	OPT_GROUP(N_("Type")), \
 	OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
@@ -772,93 +758,6 @@ static char *default_user_config(void)
 	return strbuf_detach(&buf, NULL);
 }
 
-static void location_options_init(struct config_location_options *opts,
-				  const char *prefix)
-{
-	if (!opts->source.file)
-		opts->source.file = opts->file_to_free =
-			xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
-
-	if (opts->use_global_config + opts->use_system_config +
-	    opts->use_local_config + opts->use_worktree_config +
-	    !!opts->source.file + !!opts->source.blob > 1) {
-		error(_("only one config file at a time"));
-		exit(129);
-	}
-
-	if (!startup_info->have_repository) {
-		if (opts->use_local_config)
-			die(_("--local can only be used inside a git repository"));
-		if (opts->source.blob)
-			die(_("--blob can only be used inside a git repository"));
-		if (opts->use_worktree_config)
-			die(_("--worktree can only be used inside a git repository"));
-	}
-
-	if (opts->source.file &&
-			!strcmp(opts->source.file, "-")) {
-		opts->source.file = NULL;
-		opts->source.use_stdin = 1;
-		opts->source.scope = CONFIG_SCOPE_COMMAND;
-	}
-
-	if (opts->use_global_config) {
-		opts->source.file = opts->file_to_free = git_global_config();
-		if (!opts->source.file)
-			/*
-			 * It is unknown if HOME/.gitconfig exists, so
-			 * we do not know if we should write to XDG
-			 * location; error out even if XDG_CONFIG_HOME
-			 * is set and points at a sane location.
-			 */
-			die(_("$HOME not set"));
-		opts->source.scope = CONFIG_SCOPE_GLOBAL;
-	} else if (opts->use_system_config) {
-		opts->source.file = opts->file_to_free = git_system_config();
-		opts->source.scope = CONFIG_SCOPE_SYSTEM;
-	} else if (opts->use_local_config) {
-		opts->source.file = opts->file_to_free = repo_git_path(the_repository, "config");
-		opts->source.scope = CONFIG_SCOPE_LOCAL;
-	} else if (opts->use_worktree_config) {
-		struct worktree **worktrees = get_worktrees();
-		if (the_repository->repository_format_worktree_config)
-			opts->source.file = opts->file_to_free =
-				repo_git_path(the_repository, "config.worktree");
-		else if (worktrees[0] && worktrees[1])
-			die(_("--worktree cannot be used with multiple "
-			      "working trees unless the config\n"
-			      "extension worktreeConfig is enabled. "
-			      "Please read \"CONFIGURATION FILE\"\n"
-			      "section in \"git help worktree\" for details"));
-		else
-			opts->source.file = opts->file_to_free =
-				repo_git_path(the_repository, "config");
-		opts->source.scope = CONFIG_SCOPE_LOCAL;
-		free_worktrees(worktrees);
-	} else if (opts->source.file) {
-		if (!is_absolute_path(opts->source.file) && prefix)
-			opts->source.file = opts->file_to_free =
-				prefix_filename(prefix, opts->source.file);
-		opts->source.scope = CONFIG_SCOPE_COMMAND;
-	} else if (opts->source.blob) {
-		opts->source.scope = CONFIG_SCOPE_COMMAND;
-	}
-
-	if (opts->respect_includes_opt == -1)
-		opts->options.respect_includes = !opts->source.file;
-	else
-		opts->options.respect_includes = opts->respect_includes_opt;
-	if (startup_info->have_repository) {
-		opts->options.commondir = repo_get_common_dir(the_repository);
-		opts->options.git_dir = repo_get_git_dir(the_repository);
-	}
-}
-
-static void location_options_release(struct config_location_options *opts)
-{
-	free(opts->file_to_free);
-}
-
 static void display_options_init(struct config_display_options *opts)
 {
 	if (opts->end_nul) {
@@ -885,7 +784,7 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix,
 	argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0);
 	check_argc(argc, 0, 0);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	display_options_init(&display_opts);
 
 	setup_auto_pager("config", 1);
@@ -944,7 +843,7 @@ static int cmd_config_get(int argc, const char **argv, const char *prefix,
 		    value_pattern))
 		die(_("--url= cannot be used with --all, --regexp or --value"));
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	display_options_init(&display_opts);
 
 	if (display_opts.type != TYPE_COLOR)
@@ -998,7 +897,7 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix,
 
 	comment = git_config_prepare_comment_string(comment_arg);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	check_write(&location_opts.source);
 
 	value = normalize_value(argv[0], argv[1], type, &default_kvi);
@@ -1044,7 +943,7 @@ static int cmd_config_unset(int argc, const char **argv, const char *prefix,
 	if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
 		die(_("--fixed-value only applies with 'value-pattern'"));
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	check_write(&location_opts.source);
 
 	if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
@@ -1073,7 +972,7 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	check_argc(argc, 2, 2);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	check_write(&location_opts.source);
 
 	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
@@ -1103,7 +1002,7 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	check_argc(argc, 1, 1);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	check_write(&location_opts.source);
 
 	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
@@ -1163,7 +1062,7 @@ static int cmd_config_edit(int argc, const char **argv, const char *prefix,
 	argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0);
 	check_argc(argc, 0, 0);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	check_write(&location_opts.source);
 
 	ret = show_editor(&location_opts);
@@ -1231,7 +1130,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
 			     builtin_config_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 
-	location_options_init(&location_opts, prefix);
+	location_options_init(the_repository, &location_opts, prefix);
 	display_options_init(&display_opts);
 
 	if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && display_opts.type) {
diff --git a/config.c b/config.c
index 7f6d53b473..9f1a7b45cf 100644
--- a/config.c
+++ b/config.c
@@ -35,6 +35,7 @@
 #include "strvec.h"
 #include "trace2.h"
 #include "wildmatch.h"
+#include "worktree.h"
 #include "write-or-die.h"
 
 struct config_source {
@@ -3592,3 +3593,91 @@ int lookup_config(const char **mapping, int nr_mapping, const char *var)
 	}
 	return -1;
 }
+
+void location_options_init(struct repository *repo,
+			   struct config_location_options *opts,
+			   const char *prefix)
+{
+	if (!opts->source.file)
+		opts->source.file = opts->file_to_free =
+			xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
+
+	if (opts->use_global_config + opts->use_system_config +
+	    opts->use_local_config + opts->use_worktree_config +
+	    !!opts->source.file + !!opts->source.blob > 1) {
+		error(_("only one config file at a time"));
+		exit(129);
+	}
+
+	if (!startup_info->have_repository) {
+		if (opts->use_local_config)
+			die(_("--local can only be used inside a git repository"));
+		if (opts->source.blob)
+			die(_("--blob can only be used inside a git repository"));
+		if (opts->use_worktree_config)
+			die(_("--worktree can only be used inside a git repository"));
+	}
+
+	if (opts->source.file &&
+			!strcmp(opts->source.file, "-")) {
+		opts->source.file = NULL;
+		opts->source.use_stdin = 1;
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	}
+
+	if (opts->use_global_config) {
+		opts->source.file = opts->file_to_free = git_global_config();
+		if (!opts->source.file)
+			/*
+			 * It is unknown if HOME/.gitconfig exists, so
+			 * we do not know if we should write to XDG
+			 * location; error out even if XDG_CONFIG_HOME
+			 * is set and points at a sane location.
+			 */
+			die(_("$HOME not set"));
+		opts->source.scope = CONFIG_SCOPE_GLOBAL;
+	} else if (opts->use_system_config) {
+		opts->source.file = opts->file_to_free = git_system_config();
+		opts->source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (opts->use_local_config) {
+		opts->source.file = opts->file_to_free = repo_git_path(repo, "config");
+		opts->source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (opts->use_worktree_config) {
+		struct worktree **worktrees = get_worktrees();
+		if (repo->repository_format_worktree_config)
+			opts->source.file = opts->file_to_free =
+				repo_git_path(repo, "config.worktree");
+		else if (worktrees[0] && worktrees[1])
+			die(_("--worktree cannot be used with multiple "
+			      "working trees unless the config\n"
+			      "extension worktreeConfig is enabled. "
+			      "Please read \"CONFIGURATION FILE\"\n"
+			      "section in \"git help worktree\" for details"));
+		else
+			opts->source.file = opts->file_to_free =
+				repo_git_path(repo, "config");
+		opts->source.scope = CONFIG_SCOPE_LOCAL;
+		free_worktrees(worktrees);
+	} else if (opts->source.file) {
+		if (!is_absolute_path(opts->source.file) && prefix)
+			opts->source.file = opts->file_to_free =
+				prefix_filename(prefix, opts->source.file);
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (opts->source.blob) {
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	}
+
+	if (opts->respect_includes_opt == -1)
+		opts->options.respect_includes = !opts->source.file;
+	else
+		opts->options.respect_includes = opts->respect_includes_opt;
+	if (startup_info->have_repository) {
+		opts->options.commondir = repo_get_common_dir(repo);
+		opts->options.git_dir = repo_get_git_dir(repo);
+	}
+}
+
+void location_options_release(struct config_location_options *opts)
+{
+	free(opts->file_to_free);
+}
diff --git a/config.h b/config.h
index 966a228f0e..6663964977 100644
--- a/config.h
+++ b/config.h
@@ -166,6 +166,26 @@ struct config_context {
 typedef int (*config_fn_t)(const char *, const char *,
 			   const struct config_context *, void *);
 
+struct config_location_options {
+	struct git_config_source source;
+	struct config_options options;
+	char *file_to_free;
+	int use_global_config;
+	int use_system_config;
+	int use_local_config;
+	int use_worktree_config;
+	int respect_includes_opt;
+};
+#define CONFIG_LOCATION_OPTIONS_INIT { \
+	.respect_includes_opt = -1, \
+}
+
+void location_options_init(struct repository *repo,
+			   struct config_location_options *opts,
+			   const char *prefix);
+
+void location_options_release(struct config_location_options *opts);
+
 /**
  * Read a specific file in git-config format.
  * This function takes the same callback and data parameters as `repo_config`.
-- 
gitgitgadget
Previous: Derrick StoleeNext: Derrick Stolee via GitGitGadget
Message 23 of 40 in “[RFC] config-batch: a new builtin for tools querying config”
  1. 00/11 [RFC] config-batch: a new builtin for tools querying configDerrick Stolee via GitGitGadget, Feb 4, 2026
  2. 01/11 config-batch: basic boilerplate of new builtinDerrick Stolee via GitGitGadget, Feb 4, 2026
  3. Junio C HamanoFeb 4, 2026
  4. Derrick StoleeFeb 5, 2026
  5. Kristoffer HaugsbakkFeb 5, 2026
  6. Kristoffer HaugsbakkFeb 5, 2026
  7. Jean-Noël AvilaFeb 6, 2026
  8. 02/11 config-batch: create parse loop and unknown commandDerrick Stolee via GitGitGadget, Feb 4, 2026
  9. Junio C HamanoFeb 4, 2026
  10. Kristoffer HaugsbakkFeb 5, 2026
  11. Jean-Noël AvilaFeb 6, 2026
  12. 03/11 config-batch: implement get v1Derrick Stolee via GitGitGadget, Feb 4, 2026
  13. Jean-Noël AvilaFeb 6, 2026
  14. 04/11 config-batch: create 'help' commandDerrick Stolee via GitGitGadget, Feb 4, 2026
  15. Jean-Noël AvilaFeb 6, 2026
  16. Derrick StoleeFeb 10, 2026
  17. 05/11 config-batch: add NUL-terminated I/O formatDerrick Stolee via GitGitGadget, Feb 4, 2026
  18. Kristoffer HaugsbakkFeb 5, 2026
  19. Jean-Noël AvilaFeb 6, 2026
  20. 06/11 docs: add design doc for config-batchDerrick Stolee via GitGitGadget, Feb 4, 2026
  21. Kristoffer HaugsbakkFeb 5, 2026
  22. Derrick StoleeFeb 10, 2026
  23. 07/11 config: extract location structs from builtinDerrick Stolee via GitGitGadget, Feb 4, 2026
  24. 08/11 config-batch: pass prefix through commandsDerrick Stolee via GitGitGadget, Feb 4, 2026
  25. 09/11 config-batch: add 'set' v1 commandDerrick Stolee via GitGitGadget, Feb 4, 2026
  26. Kristoffer HaugsbakkFeb 5, 2026
  27. Kristoffer HaugsbakkFeb 5, 2026
  28. Kristoffer HaugsbakkFeb 5, 2026
  29. Derrick StoleeFeb 10, 2026
  30. Jean-Noël AvilaFeb 6, 2026
  31. 10/11 t1312: create read/write testDerrick Stolee via GitGitGadget, Feb 4, 2026
  32. 11/11 config-batch: add unset v1 commandDerrick Stolee via GitGitGadget, Feb 4, 2026
  33. Kristoffer HaugsbakkFeb 5, 2026
  34. Junio C HamanoFeb 4, 2026
  35. Derrick StoleeFeb 5, 2026
  36. brian m. carlsonFeb 5, 2026
  37. Derrick StoleeFeb 5, 2026
  38. Derrick StoleeFeb 10, 2026
  39. Phillip WoodFeb 5, 2026
  40. Kristoffer HaugsbakkFeb 5, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.