config: stop using config_exclusive_filename

The git-config command sometimes operates on the default set of config files (either reading from all, or writing to repo config), and sometimes operates on a specific file. In the latter case, we set the magic global config_exclusive_filename, and the code in config.c does the right thing. Instead, let's have git-config use the "advanced" variants of config.c's functions which let it specify an individual filename (or NULL for the default). This makes the code a lot more obvious, and fixes two small bugs: 1. A relative path specified by GIT_CONFIG=foo will look in the wrong directory if we have to chdir as part of repository setup. We already handle this properly for "git config -f foo", but the GIT_CONFIG lookup used config_exclusive_filename directly. By dropping to a single magic variable, the GIT_CONFIG case now just works. 2. Calling "git config -f foo --edit" would not respect core.editor. This is because just before editing, we called git_config, which would respect the config_exclusive_filename setting, even though this particular git_config call was not about looking in the user's specified file, but rather about loading actual git config, just as any other git program would. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Feb 16, 2012 at 03:07 UTC 270a34438b0776c072268838a8e8aa786494cfee
2 files changed +60 -24
builtin/config.c
+35 -24
@@ -162,7 +162,7 @@ static int get_value(const char *key_, const char *regex_)
162 char *global = NULL, *repo_config = NULL;
163 const char *system_wide = NULL, *local;
164
165 - local = config_exclusive_filename;
165 + local = given_config_file;
166 if (!local) {
167 const char *home = getenv("HOME");
168 local = repo_config = git_pathdup("config");
@@ -301,7 +301,8 @@ static void get_color(const char *def_color)
301 {
302 get_color_found = 0;
303 parsed_color[0] = '\0';
304 - git_config(git_get_color_config, NULL);
304 + git_config_with_options(git_get_color_config, NULL,
305 + given_config_file);
306
307 if (!get_color_found && def_color)
308 color_parse(def_color, "command line", parsed_color);
@@ -328,7 +329,8 @@ static int get_colorbool(int print)
329 {
330 get_colorbool_found = -1;
331 get_diff_color_found = -1;
331 - git_config(git_get_colorbool_config, NULL);
332 + git_config_with_options(git_get_colorbool_config, NULL,
333 + given_config_file);
334
335 if (get_colorbool_found < 0) {
336 if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -351,7 +353,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
353 int nongit = !startup_info->have_repository;
354 char *value;
355
354 - config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
356 + given_config_file = getenv(CONFIG_ENVIRONMENT);
357
358 argc = parse_options(argc, argv, prefix, builtin_config_options,
359 builtin_config_usage,
@@ -366,23 +368,23 @@ int cmd_config(int argc, const char **argv, const char *prefix)
368 char *home = getenv("HOME");
369 if (home) {
370 char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
369 - config_exclusive_filename = user_config;
371 + given_config_file = user_config;
372 } else {
373 die("$HOME not set");
374 }
375 }
376 else if (use_system_config)
375 - config_exclusive_filename = git_etc_gitconfig();
377 + given_config_file = git_etc_gitconfig();
378 else if (use_local_config)
377 - config_exclusive_filename = git_pathdup("config");
379 + given_config_file = git_pathdup("config");
380 else if (given_config_file) {
381 if (!is_absolute_path(given_config_file) && prefix)
380 - config_exclusive_filename =
382 + given_config_file =
383 xstrdup(prefix_filename(prefix,
384 strlen(prefix),
385 given_config_file));
386 else
385 - config_exclusive_filename = given_config_file;
387 + given_config_file = given_config_file;
388 }
389
390 if (end_null) {
@@ -421,28 +423,29 @@ int cmd_config(int argc, const char **argv, const char *prefix)
423
424 if (actions == ACTION_LIST) {
425 check_argc(argc, 0, 0);
424 - if (git_config(show_all_config, NULL) < 0) {
425 - if (config_exclusive_filename)
426 + if (git_config_with_options(show_all_config, NULL,
427 + given_config_file) < 0) {
428 + if (given_config_file)
429 die_errno("unable to read config file '%s'",
427 - config_exclusive_filename);
430 + given_config_file);
431 else
432 die("error processing config file(s)");
433 }
434 }
435 else if (actions == ACTION_EDIT) {
436 check_argc(argc, 0, 0);
434 - if (!config_exclusive_filename && nongit)
437 + if (!given_config_file && nongit)
438 die("not in a git directory");
439 git_config(git_default_config, NULL);
437 - launch_editor(config_exclusive_filename ?
438 - config_exclusive_filename : git_path("config"),
440 + launch_editor(given_config_file ?
441 + given_config_file : git_path("config"),
442 NULL, NULL);
443 }
444 else if (actions == ACTION_SET) {
445 int ret;
446 check_argc(argc, 2, 2);
447 value = normalize_value(argv[0], argv[1]);
445 - ret = git_config_set(argv[0], value);
448 + ret = git_config_set_in_file(given_config_file, argv[0], value);
449 if (ret == CONFIG_NOTHING_SET)
450 error("cannot overwrite multiple values with a single value\n"
451 " Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -451,17 +454,20 @@ int cmd_config(int argc, const char **argv, const char *prefix)
454 else if (actions == ACTION_SET_ALL) {
455 check_argc(argc, 2, 3);
456 value = normalize_value(argv[0], argv[1]);
454 - return git_config_set_multivar(argv[0], value, argv[2], 0);
457 + return git_config_set_multivar_in_file(given_config_file,
458 + argv[0], value, argv[2], 0);
459 }
460 else if (actions == ACTION_ADD) {
461 check_argc(argc, 2, 2);
462 value = normalize_value(argv[0], argv[1]);
459 - return git_config_set_multivar(argv[0], value, "^$", 0);
463 + return git_config_set_multivar_in_file(given_config_file,
464 + argv[0], value, "^$", 0);
465 }
466 else if (actions == ACTION_REPLACE_ALL) {
467 check_argc(argc, 2, 3);
468 value = normalize_value(argv[0], argv[1]);
464 - return git_config_set_multivar(argv[0], value, argv[2], 1);
469 + return git_config_set_multivar_in_file(given_config_file,
470 + argv[0], value, argv[2], 1);
471 }
472 else if (actions == ACTION_GET) {
473 check_argc(argc, 1, 2);
@@ -482,18 +488,22 @@ int cmd_config(int argc, const char **argv, const char *prefix)
488 else if (actions == ACTION_UNSET) {
489 check_argc(argc, 1, 2);
490 if (argc == 2)
485 - return git_config_set_multivar(argv[0], NULL, argv[1], 0);
491 + return git_config_set_multivar_in_file(given_config_file,
492 + argv[0], NULL, argv[1], 0);
493 else
487 - return git_config_set(argv[0], NULL);
494 + return git_config_set_in_file(given_config_file,
495 + argv[0], NULL);
496 }
497 else if (actions == ACTION_UNSET_ALL) {
498 check_argc(argc, 1, 2);
491 - return git_config_set_multivar(argv[0], NULL, argv[1], 1);
499 + return git_config_set_multivar_in_file(given_config_file,
500 + argv[0], NULL, argv[1], 1);
501 }
502 else if (actions == ACTION_RENAME_SECTION) {
503 int ret;
504 check_argc(argc, 2, 2);
496 - ret = git_config_rename_section(argv[0], argv[1]);
505 + ret = git_config_rename_section_in_file(given_config_file,
506 + argv[0], argv[1]);
507 if (ret < 0)
508 return ret;
509 if (ret == 0)
@@ -502,7 +512,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
512 else if (actions == ACTION_REMOVE_SECTION) {
513 int ret;
514 check_argc(argc, 1, 1);
505 - ret = git_config_rename_section(argv[0], NULL);
515 + ret = git_config_rename_section_in_file(given_config_file,
516 + argv[0], NULL);
517 if (ret < 0)
518 return ret;
519 if (ret == 0)
t/t1300-repo-config.sh
+25
@@ -458,6 +458,14 @@ test_expect_success 'refer config from subdirectory' '
458
459 '
460
461 +test_expect_success 'refer config from subdirectory via GIT_CONFIG' '
462 + (
463 + cd x &&
464 + GIT_CONFIG=../other-config git config --get ein.bahn >actual &&
465 + test_cmp expect actual
466 + )
467 +'
468 +
469 cat > expect << EOF
470 [ein]
471 bahn = strasse
@@ -960,4 +968,21 @@ test_expect_success 'git -c complains about empty key and value' '
968 test_must_fail git -c "" rev-parse
969 '
970
971 +test_expect_success 'git config --edit works' '
972 + git config -f tmp test.value no &&
973 + echo test.value=yes >expect &&
974 + GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit &&
975 + git config -f tmp --list >actual &&
976 + test_cmp expect actual
977 +'
978 +
979 +test_expect_success 'git config --edit respects core.editor' '
980 + git config -f tmp test.value no &&
981 + echo test.value=yes >expect &&
982 + test_config core.editor "echo [test]value=yes >" &&
983 + git config -f tmp --edit &&
984 + git config -f tmp --list >actual &&
985 + test_cmp expect actual
986 +'
987 +
988 test_done