config.c 18.2 KB
Newer Older
1
#include "builtin.h"
2
#include "cache.h"
3
#include "color.h"
4
#include "parse-options.h"
5
#include "urlmatch.h"
6

7
static const char *const builtin_config_usage[] = {
8
	N_("git config [options]"),
9 10
	NULL
};
11

12 13 14 15 16 17 18
static char *key;
static regex_t *key_regexp;
static regex_t *regexp;
static int show_keys;
static int use_key_regexp;
static int do_all;
static int do_not_match;
19 20 21
static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
22

S
Sverre Rabbelier 已提交
23
static int use_global_config, use_system_config, use_local_config;
24
static const char *given_config_file;
25
static const char *given_config_blob;
26
static int actions, types;
27 28
static const char *get_color_slot, *get_colorbool_slot;
static int end_null;
J
Jeff King 已提交
29
static int respect_includes = -1;
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
#define ACTION_GET_REGEXP (1<<2)
#define ACTION_REPLACE_ALL (1<<3)
#define ACTION_ADD (1<<4)
#define ACTION_UNSET (1<<5)
#define ACTION_UNSET_ALL (1<<6)
#define ACTION_RENAME_SECTION (1<<7)
#define ACTION_REMOVE_SECTION (1<<8)
#define ACTION_LIST (1<<9)
#define ACTION_EDIT (1<<10)
#define ACTION_SET (1<<11)
#define ACTION_SET_ALL (1<<12)
#define ACTION_GET_COLOR (1<<13)
#define ACTION_GET_COLORBOOL (1<<14)
46
#define ACTION_GET_URLMATCH (1<<15)
47

48 49 50
#define TYPE_BOOL (1<<0)
#define TYPE_INT (1<<1)
#define TYPE_BOOL_OR_INT (1<<2)
51
#define TYPE_PATH (1<<3)
52

53
static struct option builtin_config_options[] = {
54
	OPT_GROUP(N_("Config file location")),
55 56 57
	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")),
58
	OPT_STRING('f', "file", &given_config_file, N_("file"), N_("use given config file")),
59
	OPT_STRING(0, "blob", &given_config_blob, N_("blob-id"), N_("read config from given blob object")),
60 61 62 63
	OPT_GROUP(N_("Action")),
	OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
	OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL),
	OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP),
64
	OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
65
	OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL),
66 67 68
	OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
	OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET),
	OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
69 70 71
	OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
	OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
	OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
72
	OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
73 74 75 76 77 78 79 80
	OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")),
	OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")),
	OPT_GROUP(N_("Type")),
	OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
	OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
	OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
	OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
	OPT_GROUP(N_("Other")),
81
	OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
82
	OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
83 84 85 86 87 88 89 90 91 92
	OPT_END(),
};

static void check_argc(int argc, int min, int max) {
	if (argc >= min && argc <= max)
		return;
	error("wrong number of arguments");
	usage_with_options(builtin_config_usage, builtin_config_options);
}

93
static int show_all_config(const char *key_, const char *value_, void *cb)
P
Petr Baudis 已提交
94 95
{
	if (value_)
96
		printf("%s%c%s%c", key_, delim, value_, term);
P
Petr Baudis 已提交
97
	else
98
		printf("%s%c", key_, term);
P
Petr Baudis 已提交
99 100 101
	return 0;
}

102 103 104 105 106 107
struct strbuf_list {
	struct strbuf *items;
	int nr;
	int alloc;
};

108
static int format_config(struct strbuf *buf, const char *key_, const char *value_)
109
{
110
	int must_free_vptr = 0;
111
	int must_print_delim = 0;
112 113
	char value[256];
	const char *vptr = value;
114

115 116
	strbuf_init(buf, 0);

117
	if (show_keys) {
118
		strbuf_addstr(buf, key_);
119
		must_print_delim = 1;
120
	}
121
	if (types == TYPE_INT)
122 123
		sprintf(value, "%"PRId64,
			git_config_int64(key_, value_ ? value_ : ""));
124
	else if (types == TYPE_BOOL)
125
		vptr = git_config_bool(key_, value_) ? "true" : "false";
126
	else if (types == TYPE_BOOL_OR_INT) {
J
Junio C Hamano 已提交
127 128 129 130 131 132
		int is_bool, v;
		v = git_config_bool_or_int(key_, value_, &is_bool);
		if (is_bool)
			vptr = v ? "true" : "false";
		else
			sprintf(value, "%d", v);
133
	} else if (types == TYPE_PATH) {
134 135
		if (git_config_pathname(&vptr, key_, value_) < 0)
			return -1;
136
		must_free_vptr = 1;
137 138 139 140 141 142
	} else if (value_) {
		vptr = value_;
	} else {
		/* Just show the key name */
		vptr = "";
		must_print_delim = 0;
J
Junio C Hamano 已提交
143
	}
144 145 146 147 148 149

	if (must_print_delim)
		strbuf_addch(buf, key_delim);
	strbuf_addstr(buf, vptr);
	strbuf_addch(buf, term);

150 151
	if (must_free_vptr)
		free((char *)vptr);
152 153 154
	return 0;
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static int collect_config(const char *key_, const char *value_, void *cb)
{
	struct strbuf_list *values = cb;

	if (!use_key_regexp && strcmp(key_, key))
		return 0;
	if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
		return 0;
	if (regexp != NULL &&
	    (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
		return 0;

	ALLOC_GROW(values->items, values->nr + 1, values->alloc);

	return format_config(&values->items[values->nr++], key_, value_);
}

172
static int get_value(const char *key_, const char *regex_)
173
{
174
	int ret = CONFIG_GENERIC_ERROR;
175
	struct strbuf_list values = {NULL};
176
	int i;
177

178
	if (use_key_regexp) {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
		char *tl;

		/*
		 * NEEDSWORK: this naive pattern lowercasing obviously does not
		 * work for more complex patterns like "^[^.]*Foo.*bar".
		 * Perhaps we should deprecate this altogether someday.
		 */

		key = xstrdup(key_);
		for (tl = key + strlen(key) - 1;
		     tl >= key && *tl != '.';
		     tl--)
			*tl = tolower(*tl);
		for (tl = key; *tl && *tl != '.'; tl++)
			*tl = tolower(*tl);

J
Jonas Fonseca 已提交
195
		key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
196
		if (regcomp(key_regexp, key, REG_EXTENDED)) {
197
			fprintf(stderr, "Invalid key pattern: %s\n", key_);
198 199
			free(key_regexp);
			key_regexp = NULL;
200
			ret = CONFIG_INVALID_PATTERN;
201
			goto free_strings;
202
		}
203
	} else {
204 205
		if (git_config_parse_key(key_, &key, NULL)) {
			ret = CONFIG_INVALID_KEY;
206
			goto free_strings;
207
		}
208 209
	}

210
	if (regex_) {
211 212 213 214 215
		if (regex_[0] == '!') {
			do_not_match = 1;
			regex_++;
		}

J
Jonas Fonseca 已提交
216
		regexp = (regex_t*)xmalloc(sizeof(regex_t));
217
		if (regcomp(regexp, regex_, REG_EXTENDED)) {
218
			fprintf(stderr, "Invalid pattern: %s\n", regex_);
219 220
			free(regexp);
			regexp = NULL;
221
			ret = CONFIG_INVALID_PATTERN;
222
			goto free_strings;
223 224 225
		}
	}

226
	git_config_with_options(collect_config, &values,
227 228
				given_config_file, given_config_blob,
				respect_includes);
229

230
	ret = !values.nr;
J
Jeff King 已提交
231

232 233
	for (i = 0; i < values.nr; i++) {
		struct strbuf *buf = values.items + i;
234 235
		if (do_all || i == values.nr - 1)
			fwrite(buf->buf, 1, buf->len, stdout);
236 237 238
		strbuf_release(buf);
	}
	free(values.items);
239

240
free_strings:
241
	free(key);
242 243 244 245
	if (key_regexp) {
		regfree(key_regexp);
		free(key_regexp);
	}
246 247 248
	if (regexp) {
		regfree(regexp);
		free(regexp);
249 250
	}

251
	return ret;
252
}
253

254
static char *normalize_value(const char *key, const char *value)
255 256 257 258 259 260
{
	char *normalized;

	if (!value)
		return NULL;

261 262 263 264 265 266 267
	if (types == 0 || types == TYPE_PATH)
		/*
		 * We don't do normalization for TYPE_PATH here: If
		 * the path is like ~/foobar/, we prefer to store
		 * "~/foobar/" in the config file, and to expand the ~
		 * when retrieving the value.
		 */
268 269 270
		normalized = xstrdup(value);
	else {
		normalized = xmalloc(64);
271
		if (types == TYPE_INT) {
272 273
			int64_t v = git_config_int64(key, value);
			sprintf(normalized, "%"PRId64, v);
274
		}
275
		else if (types == TYPE_BOOL)
276 277
			sprintf(normalized, "%s",
				git_config_bool(key, value) ? "true" : "false");
278
		else if (types == TYPE_BOOL_OR_INT) {
J
Junio C Hamano 已提交
279 280 281 282 283 284 285
			int is_bool, v;
			v = git_config_bool_or_int(key, value, &is_bool);
			if (!is_bool)
				sprintf(normalized, "%d", v);
			else
				sprintf(normalized, "%s", v ? "true" : "false");
		}
286 287 288 289 290
	}

	return normalized;
}

291 292
static int get_color_found;
static const char *get_color_slot;
293
static const char *get_colorbool_slot;
294 295
static char parsed_color[COLOR_MAXLEN];

296
static int git_get_color_config(const char *var, const char *value, void *cb)
297 298
{
	if (!strcmp(var, get_color_slot)) {
299 300
		if (!value)
			config_error_nonbool(var);
301 302 303 304 305 306
		color_parse(value, var, parsed_color);
		get_color_found = 1;
	}
	return 0;
}

307
static void get_color(const char *def_color)
308 309 310
{
	get_color_found = 0;
	parsed_color[0] = '\0';
311
	git_config_with_options(git_get_color_config, NULL,
312 313
				given_config_file, given_config_blob,
				respect_includes);
314 315 316 317 318 319 320

	if (!get_color_found && def_color)
		color_parse(def_color, "command line", parsed_color);

	fputs(parsed_color, stdout);
}

J
Junio C Hamano 已提交
321
static int get_colorbool_found;
322
static int get_diff_color_found;
323
static int get_color_ui_found;
324 325
static int git_get_colorbool_config(const char *var, const char *value,
		void *cb)
J
Junio C Hamano 已提交
326
{
327 328 329 330 331
	if (!strcmp(var, get_colorbool_slot))
		get_colorbool_found = git_config_colorbool(var, value);
	else if (!strcmp(var, "diff.color"))
		get_diff_color_found = git_config_colorbool(var, value);
	else if (!strcmp(var, "color.ui"))
332
		get_color_ui_found = git_config_colorbool(var, value);
J
Junio C Hamano 已提交
333 334 335
	return 0;
}

336
static int get_colorbool(int print)
J
Junio C Hamano 已提交
337
{
338 339
	get_colorbool_found = -1;
	get_diff_color_found = -1;
340
	get_color_ui_found = -1;
341
	git_config_with_options(git_get_colorbool_config, NULL,
342 343
				given_config_file, given_config_blob,
				respect_includes);
J
Junio C Hamano 已提交
344

345
	if (get_colorbool_found < 0) {
346
		if (!strcmp(get_colorbool_slot, "color.diff"))
347 348
			get_colorbool_found = get_diff_color_found;
		if (get_colorbool_found < 0)
349
			get_colorbool_found = get_color_ui_found;
350 351
	}

352 353
	if (get_colorbool_found < 0)
		/* default value if none found in config */
M
Matthieu Moy 已提交
354
		get_colorbool_found = GIT_COLOR_AUTO;
355

356 357
	get_colorbool_found = want_color(get_colorbool_found);

358
	if (print) {
J
Junio C Hamano 已提交
359 360
		printf("%s\n", get_colorbool_found ? "true" : "false");
		return 0;
361 362
	} else
		return get_colorbool_found ? 0 : 1;
J
Junio C Hamano 已提交
363 364
}

365 366 367 368 369 370
static void check_blob_write(void)
{
	if (given_config_blob)
		die("writing config blobs is not supported");
}

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
struct urlmatch_current_candidate_value {
	char value_is_null;
	struct strbuf value;
};

static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
{
	struct string_list *values = cb;
	struct string_list_item *item = string_list_insert(values, var);
	struct urlmatch_current_candidate_value *matched = item->util;

	if (!matched) {
		matched = xmalloc(sizeof(*matched));
		strbuf_init(&matched->value, 0);
		item->util = matched;
	} else {
		strbuf_reset(&matched->value);
	}

	if (value) {
		strbuf_addstr(&matched->value, value);
		matched->value_is_null = 0;
	} else {
		matched->value_is_null = 1;
	}
	return 0;
}

static char *dup_downcase(const char *string)
{
	char *result;
	size_t len, i;

	len = strlen(string);
	result = xmalloc(len + 1);
	for (i = 0; i < len; i++)
		result[i] = tolower(string[i]);
	result[i] = '\0';
	return result;
}

static int get_urlmatch(const char *var, const char *url)
{
	char *section_tail;
	struct string_list_item *item;
	struct urlmatch_config config = { STRING_LIST_INIT_DUP };
	struct string_list values = STRING_LIST_INIT_DUP;

	config.collect_fn = urlmatch_collect_fn;
	config.cascade_fn = NULL;
	config.cb = &values;

	if (!url_normalize(url, &config.url))
424
		die("%s", config.url.err);
425 426 427 428 429 430 431 432 433 434 435 436 437

	config.section = dup_downcase(var);
	section_tail = strchr(config.section, '.');
	if (section_tail) {
		*section_tail = '\0';
		config.key = section_tail + 1;
		show_keys = 0;
	} else {
		config.key = NULL;
		show_keys = 1;
	}

	git_config_with_options(urlmatch_config_entry, &config,
J
Junio C Hamano 已提交
438
				given_config_file, NULL, respect_includes);
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461

	for_each_string_list_item(item, &values) {
		struct urlmatch_current_candidate_value *matched = item->util;
		struct strbuf key = STRBUF_INIT;
		struct strbuf buf = STRBUF_INIT;

		strbuf_addstr(&key, item->string);
		format_config(&buf, key.buf,
			      matched->value_is_null ? NULL : matched->value.buf);
		fwrite(buf.buf, 1, buf.len, stdout);
		strbuf_release(&key);
		strbuf_release(&buf);

		strbuf_release(&matched->value);
	}
	string_list_clear(&config.vars, 1);
	string_list_clear(&values, 1);
	free(config.url.url);

	free((void *)config.section);
	return 0;
}

462
int cmd_config(int argc, const char **argv, const char *prefix)
463
{
464
	int nongit = !startup_info->have_repository;
465
	char *value;
466

467
	given_config_file = getenv(CONFIG_ENVIRONMENT);
468

469 470
	argc = parse_options(argc, argv, prefix, builtin_config_options,
			     builtin_config_usage,
471 472
			     PARSE_OPT_STOP_AT_NON_OPTION);

473 474
	if (use_global_config + use_system_config + use_local_config +
	    !!given_config_file + !!given_config_blob > 1) {
475 476 477 478
		error("only one config file at a time.");
		usage_with_options(builtin_config_usage, builtin_config_options);
	}

479
	if (use_global_config) {
480 481 482 483 484
		char *user_config = NULL;
		char *xdg_config = NULL;

		home_config_paths(&user_config, &xdg_config, "config");

485 486 487 488 489 490 491 492 493
		if (!user_config)
			/*
			 * 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");

494 495
		if (access_or_warn(user_config, R_OK, 0) &&
		    xdg_config && !access_or_warn(xdg_config, R_OK, 0))
496 497
			given_config_file = xdg_config;
		else
498
			given_config_file = user_config;
499 500
	}
	else if (use_system_config)
501
		given_config_file = git_etc_gitconfig();
S
Sverre Rabbelier 已提交
502
	else if (use_local_config)
503
		given_config_file = git_pathdup("config");
504 505
	else if (given_config_file) {
		if (!is_absolute_path(given_config_file) && prefix)
506
			given_config_file =
507 508 509
				xstrdup(prefix_filename(prefix,
							strlen(prefix),
							given_config_file));
510 511
	}

J
Jeff King 已提交
512 513 514
	if (respect_includes == -1)
		respect_includes = !given_config_file;

515 516 517 518 519 520
	if (end_null) {
		term = '\0';
		delim = '\n';
		key_delim = '\n';
	}

521 522 523 524 525
	if (HAS_MULTI_BITS(types)) {
		error("only one type at a time.");
		usage_with_options(builtin_config_usage, builtin_config_options);
	}

526 527 528 529 530
	if (get_color_slot)
	    actions |= ACTION_GET_COLOR;
	if (get_colorbool_slot)
	    actions |= ACTION_GET_COLORBOOL;

531 532 533 534 535
	if ((get_color_slot || get_colorbool_slot) && types) {
		error("--get-color and variable type are incoherent");
		usage_with_options(builtin_config_usage, builtin_config_options);
	}

536 537 538 539 540 541 542 543 544 545 546
	if (HAS_MULTI_BITS(actions)) {
		error("only one action at a time.");
		usage_with_options(builtin_config_usage, builtin_config_options);
	}
	if (actions == 0)
		switch (argc) {
		case 1: actions = ACTION_GET; break;
		case 2: actions = ACTION_SET; break;
		case 3: actions = ACTION_SET_ALL; break;
		default:
			usage_with_options(builtin_config_usage, builtin_config_options);
547
		}
548 549

	if (actions == ACTION_LIST) {
550
		check_argc(argc, 0, 0);
551
		if (git_config_with_options(show_all_config, NULL,
J
Jeff King 已提交
552
					    given_config_file,
553
					    given_config_blob,
J
Jeff King 已提交
554
					    respect_includes) < 0) {
555
			if (given_config_file)
556
				die_errno("unable to read config file '%s'",
557
					  given_config_file);
558 559
			else
				die("error processing config file(s)");
560
		}
561
	}
562
	else if (actions == ACTION_EDIT) {
563
		check_argc(argc, 0, 0);
564
		if (!given_config_file && nongit)
565
			die("not in a git directory");
566 567
		if (given_config_blob)
			die("editing blobs is not supported");
568
		git_config(git_default_config, NULL);
569 570
		launch_editor(given_config_file ?
			      given_config_file : git_path("config"),
571 572 573
			      NULL, NULL);
	}
	else if (actions == ACTION_SET) {
574
		int ret;
575
		check_blob_write();
576 577
		check_argc(argc, 2, 2);
		value = normalize_value(argv[0], argv[1]);
578
		ret = git_config_set_in_file(given_config_file, argv[0], value);
579 580
		if (ret == CONFIG_NOTHING_SET)
			error("cannot overwrite multiple values with a single value\n"
581
			"       Use a regexp, --add or --replace-all to change %s.", argv[0]);
582
		return ret;
583 584
	}
	else if (actions == ACTION_SET_ALL) {
585
		check_blob_write();
586 587
		check_argc(argc, 2, 3);
		value = normalize_value(argv[0], argv[1]);
588 589
		return git_config_set_multivar_in_file(given_config_file,
						       argv[0], value, argv[2], 0);
590 591
	}
	else if (actions == ACTION_ADD) {
592
		check_blob_write();
593 594
		check_argc(argc, 2, 2);
		value = normalize_value(argv[0], argv[1]);
595 596
		return git_config_set_multivar_in_file(given_config_file,
						       argv[0], value, "^$", 0);
597 598
	}
	else if (actions == ACTION_REPLACE_ALL) {
599
		check_blob_write();
600 601
		check_argc(argc, 2, 3);
		value = normalize_value(argv[0], argv[1]);
602 603
		return git_config_set_multivar_in_file(given_config_file,
						       argv[0], value, argv[2], 1);
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	}
	else if (actions == ACTION_GET) {
		check_argc(argc, 1, 2);
		return get_value(argv[0], argv[1]);
	}
	else if (actions == ACTION_GET_ALL) {
		do_all = 1;
		check_argc(argc, 1, 2);
		return get_value(argv[0], argv[1]);
	}
	else if (actions == ACTION_GET_REGEXP) {
		show_keys = 1;
		use_key_regexp = 1;
		do_all = 1;
		check_argc(argc, 1, 2);
		return get_value(argv[0], argv[1]);
	}
621 622 623 624
	else if (actions == ACTION_GET_URLMATCH) {
		check_argc(argc, 2, 2);
		return get_urlmatch(argv[0], argv[1]);
	}
625
	else if (actions == ACTION_UNSET) {
626
		check_blob_write();
627 628
		check_argc(argc, 1, 2);
		if (argc == 2)
629 630
			return git_config_set_multivar_in_file(given_config_file,
							       argv[0], NULL, argv[1], 0);
631
		else
632 633
			return git_config_set_in_file(given_config_file,
						      argv[0], NULL);
634 635
	}
	else if (actions == ACTION_UNSET_ALL) {
636
		check_blob_write();
637
		check_argc(argc, 1, 2);
638 639
		return git_config_set_multivar_in_file(given_config_file,
						       argv[0], NULL, argv[1], 1);
640 641 642
	}
	else if (actions == ACTION_RENAME_SECTION) {
		int ret;
643
		check_blob_write();
644
		check_argc(argc, 2, 2);
645 646
		ret = git_config_rename_section_in_file(given_config_file,
							argv[0], argv[1]);
647 648 649 650 651 652 653
		if (ret < 0)
			return ret;
		if (ret == 0)
			die("No such section!");
	}
	else if (actions == ACTION_REMOVE_SECTION) {
		int ret;
654
		check_blob_write();
655
		check_argc(argc, 1, 1);
656 657
		ret = git_config_rename_section_in_file(given_config_file,
							argv[0], NULL);
658 659 660 661 662 663 664 665 666 667
		if (ret < 0)
			return ret;
		if (ret == 0)
			die("No such section!");
	}
	else if (actions == ACTION_GET_COLOR) {
		get_color(argv[0]);
	}
	else if (actions == ACTION_GET_COLORBOOL) {
		if (argc == 1)
668
			color_stdout_is_tty = git_config_bool("command line", argv[0]);
669 670 671
		return get_colorbool(argc != 0);
	}

672 673
	return 0;
}