]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/config: move location options into local variables
authorPatrick Steinhardt <ps@pks.im>
Wed, 15 May 2024 06:42:16 +0000 (08:42 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 15 May 2024 14:17:53 +0000 (07:17 -0700)
The location options are tracked via a set of global variables. Move
them into a self-contained structure so that we can easily parse all
relevant options and hand them over to the various functions that
require them.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/config.c

index 155564b83297b3876823b0bfdb497fe9a164fd41..ec36d7289a478c79c8797d5cc961c7cc635724d9 100644 (file)
@@ -62,6 +62,26 @@ static const char *const builtin_config_edit_usage[] = {
        NULL
 };
 
+#define CONFIG_LOCATION_OPTIONS(opts) \
+       OPT_GROUP(N_("Config file location")), \
+       OPT_BOOL(0, "global", &opts.use_global_config, N_("use global config file")), \
+       OPT_BOOL(0, "system", &opts.use_system_config, N_("use system config file")), \
+       OPT_BOOL(0, "local", &opts.use_local_config, N_("use repository config file")), \
+       OPT_BOOL(0, "worktree", &opts.use_worktree_config, N_("use per-worktree config file")), \
+       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;
+};
+#define CONFIG_LOCATION_OPTIONS_INIT {0}
+
 static char *key;
 static regex_t *key_regexp;
 static const char *value_pattern;
@@ -75,14 +95,10 @@ static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
 
-static int use_global_config, use_system_config, use_local_config;
-static int use_worktree_config;
-static struct git_config_source given_config_source;
 static int type;
 static char *default_value;
 static int end_nul;
 static int respect_includes_opt = -1;
-static struct config_options config_options;
 static int show_origin;
 static int show_scope;
 static int fixed_value;
@@ -298,7 +314,8 @@ static int collect_config(const char *key_, const char *value_,
        return format_config(&values->items[values->nr++], key_, value_, kvi);
 }
 
-static int get_value(const char *key_, const char *regex_, unsigned flags)
+static int get_value(const struct config_location_options *opts,
+                    const char *key_, const char *regex_, unsigned flags)
 {
        int ret = CONFIG_GENERIC_ERROR;
        struct strbuf_list values = {NULL};
@@ -353,8 +370,8 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
        }
 
        config_with_options(collect_config, &values,
-                           &given_config_source, the_repository,
-                           &config_options);
+                           &opts->source, the_repository,
+                           &opts->options);
 
        if (!values.nr && default_value) {
                struct key_value_info kvi = KVI_INIT;
@@ -464,14 +481,15 @@ static int git_get_color_config(const char *var, const char *value,
        return 0;
 }
 
-static void get_color(const char *var, const char *def_color)
+static void get_color(const struct config_location_options *opts,
+                     const char *var, const char *def_color)
 {
        get_color_slot = var;
        get_color_found = 0;
        parsed_color[0] = '\0';
        config_with_options(git_get_color_config, NULL,
-                           &given_config_source, the_repository,
-                           &config_options);
+                           &opts->source, the_repository,
+                           &opts->options);
 
        if (!get_color_found && def_color) {
                if (color_parse(def_color, parsed_color) < 0)
@@ -497,15 +515,16 @@ static int git_get_colorbool_config(const char *var, const char *value,
        return 0;
 }
 
-static int get_colorbool(const char *var, int print)
+static int get_colorbool(const struct config_location_options *opts,
+                        const char *var, int print)
 {
        get_colorbool_slot = var;
        get_colorbool_found = -1;
        get_diff_color_found = -1;
        get_color_ui_found = -1;
        config_with_options(git_get_colorbool_config, NULL,
-                           &given_config_source, the_repository,
-                           &config_options);
+                           &opts->source, the_repository,
+                           &opts->options);
 
        if (get_colorbool_found < 0) {
                if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -527,15 +546,15 @@ static int get_colorbool(const char *var, int print)
                return get_colorbool_found ? 0 : 1;
 }
 
-static void check_write(void)
+static void check_write(const struct git_config_source *source)
 {
-       if (!given_config_source.file && !startup_info->have_repository)
+       if (!source->file && !startup_info->have_repository)
                die(_("not in a git directory"));
 
-       if (given_config_source.use_stdin)
+       if (source->use_stdin)
                die(_("writing to stdin is not supported"));
 
-       if (given_config_source.blob)
+       if (source->blob)
                die(_("writing config blobs is not supported"));
 }
 
@@ -572,7 +591,8 @@ static int urlmatch_collect_fn(const char *var, const char *value,
        return 0;
 }
 
-static int get_urlmatch(const char *var, const char *url)
+static int get_urlmatch(const struct config_location_options *opts,
+                       const char *var, const char *url)
 {
        int ret;
        char *section_tail;
@@ -599,8 +619,8 @@ static int get_urlmatch(const char *var, const char *url)
        }
 
        config_with_options(urlmatch_config_entry, &config,
-                           &given_config_source, the_repository,
-                           &config_options);
+                           &opts->source, the_repository,
+                           &opts->options);
 
        ret = !values.nr;
 
@@ -638,34 +658,39 @@ static char *default_user_config(void)
        return strbuf_detach(&buf, NULL);
 }
 
-static void handle_config_location(const char *prefix)
+static void location_options_init(struct config_location_options *opts,
+                                 const char *prefix)
 {
-       if (use_global_config + use_system_config + use_local_config +
-           use_worktree_config +
-           !!given_config_source.file + !!given_config_source.blob > 1) {
+       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 (use_local_config)
+               if (opts->use_local_config)
                        die(_("--local can only be used inside a git repository"));
-               if (given_config_source.blob)
+               if (opts->source.blob)
                        die(_("--blob can only be used inside a git repository"));
-               if (use_worktree_config)
+               if (opts->use_worktree_config)
                        die(_("--worktree can only be used inside a git repository"));
        }
 
-       if (given_config_source.file &&
-                       !strcmp(given_config_source.file, "-")) {
-               given_config_source.file = NULL;
-               given_config_source.use_stdin = 1;
-               given_config_source.scope = CONFIG_SCOPE_COMMAND;
+       if (opts->source.file &&
+                       !strcmp(opts->source.file, "-")) {
+               opts->source.file = NULL;
+               opts->source.use_stdin = 1;
+               opts->source.scope = CONFIG_SCOPE_COMMAND;
        }
 
-       if (use_global_config) {
-               given_config_source.file = git_global_config();
-               if (!given_config_source.file)
+       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
@@ -673,17 +698,18 @@ static void handle_config_location(const char *prefix)
                         * is set and points at a sane location.
                         */
                        die(_("$HOME not set"));
-               given_config_source.scope = CONFIG_SCOPE_GLOBAL;
-       } else if (use_system_config) {
-               given_config_source.file = git_system_config();
-               given_config_source.scope = CONFIG_SCOPE_SYSTEM;
-       } else if (use_local_config) {
-               given_config_source.file = git_pathdup("config");
-               given_config_source.scope = CONFIG_SCOPE_LOCAL;
-       } else if (use_worktree_config) {
+               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 = git_pathdup("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)
-                       given_config_source.file = git_pathdup("config.worktree");
+                       opts->source.file = opts->file_to_free =
+                               git_pathdup("config.worktree");
                else if (worktrees[0] && worktrees[1])
                        die(_("--worktree cannot be used with multiple "
                              "working trees unless the config\n"
@@ -691,28 +717,34 @@ static void handle_config_location(const char *prefix)
                              "Please read \"CONFIGURATION FILE\"\n"
                              "section in \"git help worktree\" for details"));
                else
-                       given_config_source.file = git_pathdup("config");
-               given_config_source.scope = CONFIG_SCOPE_LOCAL;
+                       opts->source.file = opts->file_to_free =
+                               git_pathdup("config");
+               opts->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;
+       } 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 (respect_includes_opt == -1)
-               config_options.respect_includes = !given_config_source.file;
+               opts->options.respect_includes = !opts->source.file;
        else
-               config_options.respect_includes = respect_includes_opt;
+               opts->options.respect_includes = respect_includes_opt;
        if (startup_info->have_repository) {
-               config_options.commondir = get_git_common_dir();
-               config_options.git_dir = get_git_dir();
+               opts->options.commondir = get_git_common_dir();
+               opts->options.git_dir = get_git_dir();
        }
 }
 
+static void location_options_release(struct config_location_options *opts)
+{
+       free(opts->file_to_free);
+}
+
 static void handle_nul(void) {
        if (end_nul) {
                term = '\0';
@@ -721,15 +753,6 @@ static void handle_nul(void) {
        }
 }
 
-#define CONFIG_LOCATION_OPTIONS \
-       OPT_GROUP(N_("Config file location")), \
-       OPT_BOOL(0, "global", &use_global_config, N_("use global config file")), \
-       OPT_BOOL(0, "system", &use_system_config, N_("use system config file")), \
-       OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")), \
-       OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")), \
-       OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), \
-       OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object"))
-
 #define CONFIG_TYPE_OPTIONS \
        OPT_GROUP(N_("Type")), \
        OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
@@ -749,8 +772,9 @@ static void handle_nul(void) {
 
 static int cmd_config_list(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                CONFIG_DISPLAY_OPTIONS,
                OPT_GROUP(N_("Other")),
                OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
@@ -760,30 +784,32 @@ 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);
 
-       handle_config_location(prefix);
+       location_options_init(&location_opts, prefix);
        handle_nul();
 
        setup_auto_pager("config", 1);
 
        if (config_with_options(show_all_config, NULL,
-                               &given_config_source, the_repository,
-                               &config_options) < 0) {
-               if (given_config_source.file)
+                               &location_opts.source, the_repository,
+                               &location_opts.options) < 0) {
+               if (location_opts.source.file)
                        die_errno(_("unable to read config file '%s'"),
-                                 given_config_source.file);
+                                 location_opts.source.file);
                else
                        die(_("error processing config file(s)"));
        }
 
+       location_options_release(&location_opts);
        return 0;
 }
 
 static int cmd_config_get(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        const char *value_pattern = NULL, *url = NULL;
        int flags = 0;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                CONFIG_TYPE_OPTIONS,
                OPT_GROUP(N_("Filter options")),
                OPT_BOOL(0, "all", &do_all, N_("return all values for multi-valued config options")),
@@ -811,26 +837,28 @@ static int cmd_config_get(int argc, const char **argv, const char *prefix)
        if (url && (do_all || use_key_regexp || value_pattern))
                die(_("--url= cannot be used with --all, --regexp or --value"));
 
-       handle_config_location(prefix);
+       location_options_init(&location_opts, prefix);
        handle_nul();
 
        setup_auto_pager("config", 1);
 
        if (url)
-               ret = get_urlmatch(argv[0], url);
+               ret = get_urlmatch(&location_opts, argv[0], url);
        else
-               ret = get_value(argv[0], value_pattern, flags);
+               ret = get_value(&location_opts, argv[0], value_pattern, flags);
 
+       location_options_release(&location_opts);
        return ret;
 }
 
 static int cmd_config_set(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        const char *value_pattern = NULL, *comment_arg = NULL;
        char *comment = NULL;
        int flags = 0, append = 0;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                CONFIG_TYPE_OPTIONS,
                OPT_GROUP(N_("Filter")),
                OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
@@ -858,23 +886,24 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix)
 
        comment = git_config_prepare_comment_string(comment_arg);
 
-       handle_config_location(prefix);
-       check_write();
+       location_options_init(&location_opts, prefix);
+       check_write(&location_opts.source);
 
        value = normalize_value(argv[0], argv[1], &default_kvi);
 
        if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], value, value_pattern,
                                                             comment, flags);
        } else {
-               ret = git_config_set_in_file_gently(given_config_source.file,
+               ret = git_config_set_in_file_gently(location_opts.source.file,
                                                    argv[0], comment, value);
                if (ret == CONFIG_NOTHING_SET)
                        error(_("cannot overwrite multiple values with a single value\n"
                        "       Use a regexp, --add or --replace-all to change %s."), argv[0]);
        }
 
+       location_options_release(&location_opts);
        free(comment);
        free(value);
        return ret;
@@ -882,10 +911,11 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix)
 
 static int cmd_config_unset(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        const char *value_pattern = NULL;
        int flags = 0;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                OPT_GROUP(N_("Filter")),
                OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
                OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
@@ -901,24 +931,26 @@ 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'"));
 
-       handle_config_location(prefix);
-       check_write();
+       location_options_init(&location_opts, prefix);
+       check_write(&location_opts.source);
 
        if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], NULL, value_pattern,
                                                             NULL, flags);
        else
-               ret = git_config_set_in_file_gently(given_config_source.file, argv[0],
+               ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
                                                    NULL, NULL);
 
+       location_options_release(&location_opts);
        return ret;
 }
 
 static int cmd_config_rename_section(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                OPT_END(),
        };
        int ret;
@@ -927,10 +959,10 @@ 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);
 
-       handle_config_location(prefix);
-       check_write();
+       location_options_init(&location_opts, prefix);
+       check_write(&location_opts.source);
 
-       ret = git_config_rename_section_in_file(given_config_source.file,
+       ret = git_config_rename_section_in_file(location_opts.source.file,
                                                argv[0], argv[1]);
        if (ret < 0)
                goto out;
@@ -939,13 +971,15 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr
        ret = 0;
 
 out:
+       location_options_release(&location_opts);
        return ret;
 }
 
 static int cmd_config_remove_section(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                OPT_END(),
        };
        int ret;
@@ -954,10 +988,10 @@ 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);
 
-       handle_config_location(prefix);
-       check_write();
+       location_options_init(&location_opts, prefix);
+       check_write(&location_opts.source);
 
-       ret = git_config_rename_section_in_file(given_config_source.file,
+       ret = git_config_rename_section_in_file(location_opts.source.file,
                                                argv[0], NULL);
        if (ret < 0)
                goto out;
@@ -966,24 +1000,25 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr
        ret = 0;
 
 out:
+       location_options_release(&location_opts);
        return ret;
 }
 
-static int show_editor(void)
+static int show_editor(struct config_location_options *opts)
 {
        char *config_file;
 
-       if (!given_config_source.file && !startup_info->have_repository)
+       if (!opts->source.file && !startup_info->have_repository)
                die(_("not in a git directory"));
-       if (given_config_source.use_stdin)
+       if (opts->source.use_stdin)
                die(_("editing stdin is not supported"));
-       if (given_config_source.blob)
+       if (opts->source.blob)
                die(_("editing blobs is not supported"));
        git_config(git_default_config, NULL);
-       config_file = given_config_source.file ?
-                       xstrdup(given_config_source.file) :
+       config_file = opts->source.file ?
+                       xstrdup(opts->source.file) :
                        git_pathdup("config");
-       if (use_global_config) {
+       if (opts->use_global_config) {
                int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
                if (fd >= 0) {
                        char *content = default_user_config();
@@ -1002,18 +1037,22 @@ static int show_editor(void)
 
 static int cmd_config_edit(int argc, const char **argv, const char *prefix)
 {
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                OPT_END(),
        };
+       int ret;
 
        argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0);
        check_argc(argc, 0, 0);
 
-       handle_config_location(prefix);
-       check_write();
+       location_options_init(&location_opts, prefix);
+       check_write(&location_opts.source);
 
-       return show_editor();
+       ret = show_editor(&location_opts);
+       location_options_release(&location_opts);
+       return ret;
 }
 
 static int cmd_config_actions(int argc, const char **argv, const char *prefix)
@@ -1036,10 +1075,11 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
                ACTION_GET_COLORBOOL = (1<<14),
                ACTION_GET_URLMATCH = (1<<15),
        };
+       struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
        const char *comment_arg = NULL;
        int actions = 0;
        struct option opts[] = {
-               CONFIG_LOCATION_OPTIONS,
+               CONFIG_LOCATION_OPTIONS(location_opts),
                OPT_GROUP(N_("Action")),
                OPT_CMDMODE(0, "get", &actions, N_("get value: name [<value-pattern>]"), ACTION_GET),
                OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key [<value-pattern>]"), ACTION_GET_ALL),
@@ -1073,7 +1113,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
                             builtin_config_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
 
-       handle_config_location(prefix);
+       location_options_init(&location_opts, prefix);
        handle_nul();
 
        if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
@@ -1162,94 +1202,94 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
        if (actions == ACTION_LIST) {
                check_argc(argc, 0, 0);
                if (config_with_options(show_all_config, NULL,
-                                       &given_config_source, the_repository,
-                                       &config_options) < 0) {
-                       if (given_config_source.file)
+                                       &location_opts.source, the_repository,
+                                       &location_opts.options) < 0) {
+                       if (location_opts.source.file)
                                die_errno(_("unable to read config file '%s'"),
-                                         given_config_source.file);
+                                         location_opts.source.file);
                        else
                                die(_("error processing config file(s)"));
                }
        }
        else if (actions == ACTION_EDIT) {
-               ret = show_editor();
+               ret = show_editor(&location_opts);
        }
        else if (actions == ACTION_SET) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1], &default_kvi);
-               ret = git_config_set_in_file_gently(given_config_source.file, argv[0], comment, value);
+               ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
                if (ret == CONFIG_NOTHING_SET)
                        error(_("cannot overwrite multiple values with a single value\n"
                        "       Use a regexp, --add or --replace-all to change %s."), argv[0]);
        }
        else if (actions == ACTION_SET_ALL) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1], &default_kvi);
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], value, argv[2],
                                                             comment, flags);
        }
        else if (actions == ACTION_ADD) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1], &default_kvi);
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], value,
                                                             CONFIG_REGEX_NONE,
                                                             comment, flags);
        }
        else if (actions == ACTION_REPLACE_ALL) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1], &default_kvi);
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], value, argv[2],
                                                             comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
        }
        else if (actions == ACTION_GET) {
                check_argc(argc, 1, 2);
-               ret = get_value(argv[0], argv[1], flags);
+               ret = get_value(&location_opts, argv[0], argv[1], flags);
        }
        else if (actions == ACTION_GET_ALL) {
                do_all = 1;
                check_argc(argc, 1, 2);
-               ret = get_value(argv[0], argv[1], flags);
+               ret = get_value(&location_opts, argv[0], argv[1], flags);
        }
        else if (actions == ACTION_GET_REGEXP) {
                show_keys = 1;
                use_key_regexp = 1;
                do_all = 1;
                check_argc(argc, 1, 2);
-               ret = get_value(argv[0], argv[1], flags);
+               ret = get_value(&location_opts, argv[0], argv[1], flags);
        }
        else if (actions == ACTION_GET_URLMATCH) {
                check_argc(argc, 2, 2);
-               ret = get_urlmatch(argv[0], argv[1]);
+               ret = get_urlmatch(&location_opts, argv[0], argv[1]);
        }
        else if (actions == ACTION_UNSET) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 1, 2);
                if (argc == 2)
-                       ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+                       ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                                     argv[0], NULL, argv[1],
                                                                     NULL, flags);
                else
-                       ret = git_config_set_in_file_gently(given_config_source.file,
+                       ret = git_config_set_in_file_gently(location_opts.source.file,
                                                            argv[0], NULL, NULL);
        }
        else if (actions == ACTION_UNSET_ALL) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 1, 2);
-               ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+               ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
                                                             argv[0], NULL, argv[1],
                                                             NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
        }
        else if (actions == ACTION_RENAME_SECTION) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 2, 2);
-               ret = git_config_rename_section_in_file(given_config_source.file,
+               ret = git_config_rename_section_in_file(location_opts.source.file,
                                                        argv[0], argv[1]);
                if (ret < 0)
                        goto out;
@@ -1259,9 +1299,9 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
                        ret = 0;
        }
        else if (actions == ACTION_REMOVE_SECTION) {
-               check_write();
+               check_write(&location_opts.source);
                check_argc(argc, 1, 1);
-               ret = git_config_rename_section_in_file(given_config_source.file,
+               ret = git_config_rename_section_in_file(location_opts.source.file,
                                                        argv[0], NULL);
                if (ret < 0)
                        goto out;
@@ -1272,16 +1312,17 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
        }
        else if (actions == ACTION_GET_COLOR) {
                check_argc(argc, 1, 2);
-               get_color(argv[0], argv[1]);
+               get_color(&location_opts, argv[0], argv[1]);
        }
        else if (actions == ACTION_GET_COLORBOOL) {
                check_argc(argc, 1, 2);
                if (argc == 2)
                        color_stdout_is_tty = git_config_bool("command line", argv[1]);
-               ret = get_colorbool(argv[0], argc == 2);
+               ret = get_colorbool(&location_opts, argv[0], argc == 2);
        }
 
 out:
+       location_options_release(&location_opts);
        free(comment);
        free(value);
        return ret;
@@ -1301,8 +1342,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                OPT_END(),
        };
 
-       given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
-
        /*
         * This is somewhat hacky: we first parse the command line while
         * keeping all args intact in order to determine whether a subcommand