From patchwork Mon May 6 08:55:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655171 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A4F91420CC for ; Mon, 6 May 2024 08:56:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985765; cv=none; b=ddo78ndp9F3MsuRvbL6GkgLOmTR0GhlRiVjPY30DLS64sbUTtQBmjerMlBQoTZVv75jpW+C7CJa3E9x1BMfVPwfJ2maZcf6WX17gTjzHKDzAETVAMad2clNfLfimtO6zIQ1yzZpUCwxGC7pkG+qJAmn4q5kWYCwcUcSPjLfuC+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985765; c=relaxed/simple; bh=BiNrHvwoTLRRTF6OHbcyN3rxPF0JayGxnQ8pBO9UKAA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=Kk/O/KZOO66WDNX3Km+daPJFESpOaudIRnc42O1HXYRaETOmR8KRGsJlFXAifAszjFjla0n/TRk5PPAebH16oH7owWsrUmA8vAIpGquFHajXokhijya4lQ4KP+LxGte8bX8TpsSZ1SILz6aFtdz/6zhYPcJhY+IbrmdfT81Yccs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=eeJzwWvb; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=CwUFcx5j; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="eeJzwWvb"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="CwUFcx5j" Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.west.internal (Postfix) with ESMTP id B5EF71800087; Mon, 6 May 2024 04:56:01 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Mon, 06 May 2024 04:56:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985761; x=1715072161; bh=YHhsVFupoN /dJT89AUFNXki2jckbC2sSFswvSzD1MGc=; b=eeJzwWvbwFzzW4WxYm92atvdhi An0d8FteoIi8+VP6HGwYe1DDs7JMeS5012mM5KiFMQiw9Ay9F8sSYCSNJfzDec+l gTbvQaItPU8zrZIsXoaXJrSCqyZRqQKolD9slKp7I539O+7MrvbFX03FAtqMvX6s vjvDQHrP0evSQ2S9PPcjocPGrFcsmK5hp8ielODdGADBE1Hwve9mEkNwoAS3gu94 HhHBy18IISj0gWcGnOTEu6V6dmZDuv3Tpxtwk/u6rvyuB7UuxzLDdm8PKWd7P5tH dWg59iiym7eggkmOHFQUFY/hIjsAkwKPFcxDSxfW3woAp+GPOOzRKaDDDVEw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985761; x=1715072161; bh=YHhsVFupoN/dJT89AUFNXki2jckb C2sSFswvSzD1MGc=; b=CwUFcx5jEg4yBWW/1SHjBu8N08ohTn25JGSiUhc1HUJ3 2a8gtf15g4MRnACiyNI8Ld+NOTcov3fnjim1T3CO1w2HquvlTueuVntY5JuDl/yL Bk2F30aVuYYq41MgqLpzZoDSKUCV2RgLmH1t8xxJAWKlA7HDUHMA46VJV99kaqLW LtkiSptyuSDQ8vNj/1ne6PxL88eWKYvBdyeeD5lPm1QYOZC+NOMy8OJSnzWz80Mf EDwXKLAw4q+lLqkkzPHobTEA9wqmneuJwupHmSw5ZA5s2PQinxC1vM5XdBlein2t eBsGo97YkszWw47kl4M/HX1NVvsVxovHqX2QPMhYpg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:55:59 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 38d6c36f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:55:53 +0000 (UTC) Date: Mon, 6 May 2024 10:55:56 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 01/14] config: clarify memory ownership when preparing comment strings Message-ID: <881d2b5426e2ee690e5ef37cd795b7141064d05f.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The ownership of memory returned when preparing a comment string is quite intricate: when the returned value is different than the passed value, then the caller is responsible to free the memory. This is quite subtle, and it's even easier to miss because the returned value is in fact a `const char *`. Adapt the function to always return either `NULL` or a newly allocated string. The function is called at most once per git-config(1), so it's not like this micro-optimization really matters. Thus, callers are now always responsible for freeing the value. Signed-off-by: Patrick Steinhardt --- builtin/config.c | 11 ++++++----- config.c | 16 ++++++---------- config.h | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 0015620dde..40456c0770 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -44,7 +44,7 @@ static struct config_options config_options; static int show_origin; static int show_scope; static int fixed_value; -static const char *comment; +static const char *comment_arg; #define ACTION_GET (1<<0) #define ACTION_GET_ALL (1<<1) @@ -174,7 +174,7 @@ static struct option builtin_config_options[] = { 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_STRING(0, "comment", &comment, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), OPT_END(), }; @@ -674,7 +674,7 @@ static char *default_user_config(void) int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; - char *value = NULL; + char *value = NULL, *comment = NULL; int flags = 0; int ret = 0; struct key_value_info default_kvi = KVI_INIT; @@ -799,7 +799,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_builtin_config(); } - if (comment && + if (comment_arg && !(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) { error(_("--comment is only applicable to add/set/replace operations")); usage_builtin_config(); @@ -841,7 +841,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) flags |= CONFIG_FLAGS_FIXED_VALUE; } - comment = git_config_prepare_comment_string(comment); + comment = git_config_prepare_comment_string(comment_arg); if (actions & PAGING_ACTIONS) setup_auto_pager("config", 1); @@ -993,6 +993,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) return get_colorbool(argv[0], argc == 2); } + free(comment); free(value); return ret; } diff --git a/config.c b/config.c index ae3652b08f..13cf9eeb16 100644 --- a/config.c +++ b/config.c @@ -3182,14 +3182,10 @@ void git_config_set(const char *key, const char *value) trace2_cmd_set_config(key, value); } -/* - * The ownership rule is that the caller will own the string - * if it receives a piece of memory different from what it passed - * as the parameter. - */ -const char *git_config_prepare_comment_string(const char *comment) +char *git_config_prepare_comment_string(const char *comment) { size_t leading_blanks; + char *prepared; if (!comment) return NULL; @@ -3210,13 +3206,13 @@ const char *git_config_prepare_comment_string(const char *comment) leading_blanks = strspn(comment, " \t"); if (leading_blanks && comment[leading_blanks] == '#') - ; /* use it as-is */ + prepared = xstrdup(comment); /* use it as-is */ else if (comment[0] == '#') - comment = xstrfmt(" %s", comment); + prepared = xstrfmt(" %s", comment); else - comment = xstrfmt(" # %s", comment); + prepared = xstrfmt(" # %s", comment); - return comment; + return prepared; } static void validate_comment_string(const char *comment) diff --git a/config.h b/config.h index f4966e3749..db8b608064 100644 --- a/config.h +++ b/config.h @@ -338,7 +338,7 @@ void git_config_set_multivar(const char *, const char *, const char *, unsigned) int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned); int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, const char *, unsigned); -const char *git_config_prepare_comment_string(const char *); +char *git_config_prepare_comment_string(const char *); /** * takes four parameters: From patchwork Mon May 6 08:56:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655172 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BBA461422D0 for ; Mon, 6 May 2024 08:56:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985768; cv=none; b=qd4c32wDURYgy9+KWHe45I0irzyvCT2INFFrcOeEuiUBvgFNSCcbpVs3KgYJUJcxqhnOKuk+V4GTS1qRaomWa/Z5uQC8BisDyY6vg4I1Ku1jSyokBc/7YEeYKgWQGKLBR3YA3kjh7Pb0XBVfkQYSSCH65qzaTmn0YWPDOmU267Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985768; c=relaxed/simple; bh=6etdAgSWj4meRdjK+uVxCbS5oItwKye7W7wmWYmb8Bk=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=nMW2Cgtdsn2Nyp8wswdV+oDCTsDXWBrtXYpJ/5LmDoA3LMn1tb58XX/lKFla7oQvTCOR61g3uYKA00vhu66J+xkZh01nP+Wsr/LeFeDo/uc1fqcHgFN9oOtW+2bGhupMPn34klya2Hdy8Mo8CCcSwoC3gYQesF8+tG2Hjp2CX4k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=kItNCuFF; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Vb1VM/oE; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="kItNCuFF"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Vb1VM/oE" Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.west.internal (Postfix) with ESMTP id AD2EB18000CA; Mon, 6 May 2024 04:56:05 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Mon, 06 May 2024 04:56:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985765; x=1715072165; bh=Pqpduzf8+t fwg9m/QAtvDiTyGtH7lLI/oHaS37Sw7k8=; b=kItNCuFFDLd4NIukLZD0Zv45t8 7V07UYZdWVobDSX4mu8ErLclZ09kD455+913leP7CICYZ/6S2MIZkn0+dkBDBMD+ fMuR5b8uJOem8liqsQWRe2+xsqsq0kMFX9mA580WNDT8k+alTbYiXWNekF8XJpDw z9jl1DXHmqIahC7eq72jfxqC4hA3i4hcBigl9P7s/S2g0Khr0VSBFd3NGxRWKME5 Y/CQIH0P5fr88NZHW8BLz3TE3jcRwm7elYkC/UK1rzzzLCDxaz9uUgY0azshyogs sm/iqZiw/w27HA0UB/mAx1j9Joe3I4l9IX9w3b9Ndh3+hSHbfgbe2mr4pMVQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985765; x=1715072165; bh=Pqpduzf8+tfwg9m/QAtvDiTyGtH7 lLI/oHaS37Sw7k8=; b=Vb1VM/oEEZT2AAufHKXz2ga1emRqh979xjMyo1hkkkEj hn8GgeZ/cjYt1meossE8w46mzuVQvZUGbDK4LHXDE2zsF/bsjR0AQbzTp5otL1Sf vq+qxKCnajdKxNh4r627uKycF+GATY5Urqw9FZXk3lAbRj69lo2MBFex9la12Kru 8w33VOjTDnGTNHwwH/vT0TiGyDAQlXq+IjIFAhDc9X44lq814YU42CO4Ek+6KiWo Wc1rbnKtMfgyoV/iIo/jrZIHQNq7kqa9maXaJoss5nz3WA+D2Su318i+f917+8sl 3HptGfPWOuVJbUsADJo3vCP9YozPJocJXxuTVHEO4g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:03 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id be89370b (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:55:57 +0000 (UTC) Date: Mon, 6 May 2024 10:56:00 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 02/14] builtin/config: move option array around Message-ID: <66dffaa8f2e4c717ca08123bad70093b25360a2a.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Move around the option array. This will help us with a follow-up commit that introduces subcommands to git-config(1). Signed-off-by: Patrick Steinhardt --- builtin/config.c | 96 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 40456c0770..59ae5996eb 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -135,54 +135,6 @@ static int option_parse_type(const struct option *opt, const char *arg, return 0; } -static struct option builtin_config_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")), - OPT_GROUP(N_("Action")), - OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET), - OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL), - OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP), - OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), - OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL), - 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-pattern]"), ACTION_UNSET), - OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL), - 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), - OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), - OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), - OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), - OPT_GROUP(N_("Type")), - OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), - OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), - OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), - OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), - OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), - 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_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 (worktree, local, global, system, command)")), - OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), - OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), - OPT_END(), -}; - -static NORETURN void usage_builtin_config(void) -{ - usage_with_options(builtin_config_usage, builtin_config_options); -} - static void check_argc(int argc, int min, int max) { if (argc >= min && argc <= max) @@ -671,6 +623,54 @@ static char *default_user_config(void) return strbuf_detach(&buf, NULL); } +static struct option builtin_config_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")), + OPT_GROUP(N_("Action")), + OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET), + OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL), + OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP), + OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), + OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL), + 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-pattern]"), ACTION_UNSET), + OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL), + 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), + OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), + OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), + OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), + OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), + OPT_GROUP(N_("Type")), + OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), + OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), + OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), + OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), + OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), + 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_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 (worktree, local, global, system, command)")), + OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_END(), +}; + +static NORETURN void usage_builtin_config(void) +{ + usage_with_options(builtin_config_usage, builtin_config_options); +} + int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; From patchwork Mon May 6 08:56:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655173 Received: from wfout3-smtp.messagingengine.com (wfout3-smtp.messagingengine.com [64.147.123.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 011151422C8 for ; Mon, 6 May 2024 08:56:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985772; cv=none; b=guzlumiM0HypBV1+ipTThTv8WGu43j0FAgSRKFHLXCL9KN4ktoYir2u22xfWSGO9JemBo2UgcUoEqBtZPuC6ebEmnxWc82XDf2z1ABuTcOaZ1Gf8WDKxePUdr9+EK9P828VzXKxDU4eserkyYYR/ZZH9NEFvbv+j13X0Fqq522c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985772; c=relaxed/simple; bh=Ss1VB/uUENm5md1f3EGbXrTdcBpiUElKICUKS/UY3JY=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=N8ghnTwUJFBK2BpD5gkWwRqahOuiix1bokf3JTRi7iEKKSZxBND1n2XEaHgQGaPpfzIX/c8CKDPo9PNqtVAxYOjwXdxwWIf9jrWa6Z1Eqbuz4n+UbbxaOujqpIB0+8K3g8n2CgQC1iLhTy6pYaeAA0uzO5/8bv12B6LNixD0fLk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=RAtoBt2c; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=EgHGwavR; arc=none smtp.client-ip=64.147.123.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="RAtoBt2c"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="EgHGwavR" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfout.west.internal (Postfix) with ESMTP id 9DE651C0012D; Mon, 6 May 2024 04:56:09 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 06 May 2024 04:56:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985769; x=1715072169; bh=gwC+j5Czuy 0VX22T5SwqguHl2Mx1/wA+6DXwHuM52uw=; b=RAtoBt2c1bZLCxMM+iJgG72Kzl ALmzQ+HChL5kVNBsMo4eDBfhmZS7SBHxs8EG0gqJ8Hr9+ke3PqtmJybWJDlw0vRj WaPT6QUCQ2BrbzeLkmOaQ/ZnW2Q88aUggboQhoFgA9diqi9+ox9PPSNSjVPz3bWt J9kWKLSkx0Vlm8NIsXzFF/RK78ai3C5AodCRt2Fa0zmi0YgcAp7ScTN14suv4OXC kcxzpCZT8ChDGdz9k4jxFgfOMmJejc7ETTunsWWIrh9rBrPzNCq3G+8SCaQUgzpn 4lf/78OwriFiDN0E+8RsMFExFUy1z75MbX1kmJausthsyHw5j+1cUgX01jLw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985769; x=1715072169; bh=gwC+j5Czuy0VX22T5SwqguHl2Mx1 /wA+6DXwHuM52uw=; b=EgHGwavRQvvs9UkVBzdFHg5evrVFZRd6J3Z8CxMhyYQ7 SnU7WVCclf10WbTKEFuKcehS7eO5kEuBkWy+Caax8/43AJ6luCYzYIvEeVC3t46f Wl8xdFv2reEYceDi8DgWnMDFYy9ATF9ctDQKcyuZFjd/P1tI7LXkBcnequ6+SsDf XuNIM4qVghBZ9NoG7hNljFDHVz/dRVo0wO2kYqTr+ozAnj3Flo4+60i0sr/Ev3OD 7G3Qks0xoN3naDcOChxAKNclqvGhJgRyhHb62EG5YW69QjMCFD0ARgbq33ZqPkG4 0FXJEVFUAkIOpP2T5OKntdn5qNtX7doRxPjChI7mng== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:07 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id b3e24957 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:02 +0000 (UTC) Date: Mon, 6 May 2024 10:56:05 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 03/14] builtin/config: move "fixed-value" option to correct group Message-ID: <36abda0e02016eac027f4fb59cd912f2c5b60e05.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The `--fixed-value` option can be used to alter how the value-pattern parameter is interpreted for the various actions of git-config(1). But while it is an option, it is currently listed as part of the actions group, which is wrong. Move the option to the "Other" group, which hosts the various options known to git-config(1). Signed-off-by: Patrick Steinhardt --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 59ae5996eb..054019b70c 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -643,7 +643,6 @@ static struct option builtin_config_options[] = { 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), - OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), @@ -663,6 +662,7 @@ static struct option builtin_config_options[] = { 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_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), OPT_END(), }; From patchwork Mon May 6 08:56:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655174 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E0F291420DE for ; Mon, 6 May 2024 08:56:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985777; cv=none; b=PebgJ6eFB0GDmHeMe7jdZV/gq4xaCustuLDBNbGygWd+STCtVPR/Yfw0NtYKOo/v3r4IZ0PRWqdf0NYbdZc4TCBlKJd5N/opgZFinQBsagpcy9llRcPGKVQjmc5r/5+sXTKHSzFzuavl6TzKvsVI3UyMjP/zCKWKRiEdQsWZd/4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985777; c=relaxed/simple; bh=puDoClsU04jpz74LIsJGT47S936YbKyzzygcaiTn2os=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=nggBmdebcwJ1agkL6yH8YbMAcHrFgOLmlXzZ5iQChMU7arw0viTApSJp81Mb28d6vYweTpKFtHj+DrHp+Sc/n1mCsIIvmeUQD7k5GwSs9jXsK+6vKWsMOcptYSJgx5O5G8PUOxxGb/hGvYQdRZ13cRR4nk6MqZm1wfQ/DOoD1FQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=EPnn95Os; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=RHV53I0d; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="EPnn95Os"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="RHV53I0d" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfhigh.west.internal (Postfix) with ESMTP id 8352218000CC; Mon, 6 May 2024 04:56:14 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 06 May 2024 04:56:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985774; x=1715072174; bh=DOGCGjhOnw nwCf4ERCd1BX6OtTk0w+YcE/AbOq90+2k=; b=EPnn95OsipkBRTE4kOmAgpQlyu MSo98AxK4U8xMdHxXXh0xSrwfdYjg6IDPOH4pnaTYX4hqHtB9bU7DHeLqO+gJcUm faHuaEm/73eVIRB0xjiDKnrHvoLiuHEb6HwJ4RIscxwB8VmQabd38z5y6rNsbRY0 fVQIcS4Tzh5Xsp4rskpme1iBV+EXhVS+Wad9amXLEIp/SMxutg6FqBDp0jG0KCEt 3BEdob+1jb+ALmfGsgcmhOpYavzCMhpHiDQRKP1k62DfoRWi+43Qz6ATAhQx0iKx ph2yeIHVHe1VjDbqmNeORlCaVX06Xu6cmyuUgrnv9bGCqvLFtKQqPBvUl8ZA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985774; x=1715072174; bh=DOGCGjhOnwnwCf4ERCd1BX6OtTk0 w+YcE/AbOq90+2k=; b=RHV53I0dEF0TzEv5y4f8Ewy8JXepwvsJlI4hl0dnGKOx LZy0yew96xBpWSoNFMpccaaREdxJpg1p6yyYVokDWYSUWa0RJQWYn9HOaX2eWpG+ LGi/XxnYr0AbxZDWZgj7ZCu4WIlTskCKVQyAoxwfPw8TXb2DdVYWVaUTajte7TMF +Abi6t3BhMEGtNotri9+SzEsA5sMIl4ZqJcz3z+rzq5hMk1eKsZTj8h/HbPVXzhv rfFZ7D1TYWYYf0Ncq3gn3rZe2+0P06ZlSQv6uu5yb40NktVOud3rEHCysJMpuDTQ IYavNQZ5MK2KUy8LQXbGYJIB6I0QoqdXk5BIZn/VIw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:12 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id c2e191da (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:06 +0000 (UTC) Date: Mon, 6 May 2024 10:56:10 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 04/14] builtin/config: use `OPT_CMDMODE()` to specify modes Message-ID: <34b66f9c8754e4cd8df934aa4d6ffdc51129e402.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The git-config(1) command has various different modes which are accessible via e.g. `--get-urlmatch` or `--unset-all`. These modes are declared with `OPT_BIT()`, which causes two minor issues: - The respective modes also have a negated form `--no-get-urlmatch`, which is unintended. - We have to manually handle exclusiveness of the modes. Switch these options to instead use `OPT_CMDMODE()`, which is made exactly for this usecase. Remove the now-unneeded check that only a single mode is given, which is now handled by the parse-options interface. While at it, format optional placeholders for arguments to conform to our style guidelines by using `[]`. Signed-off-by: Patrick Steinhardt --- builtin/config.c | 32 ++++++++++++++------------------ t/t1300-config.sh | 13 +++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 054019b70c..8991533e08 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -632,20 +632,20 @@ static struct option builtin_config_options[] = { 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")), OPT_GROUP(N_("Action")), - OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET), - OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL), - OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP), - OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), - OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL), - 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-pattern]"), ACTION_UNSET), - OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL), - 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), - OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), - OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), + OPT_CMDMODE(0, "get", &actions, N_("get value: name []"), ACTION_GET), + OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key []"), ACTION_GET_ALL), + OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex []"), ACTION_GET_REGEXP), + OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), + OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value []"), ACTION_REPLACE_ALL), + OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), + OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name []"), ACTION_UNSET), + OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name []"), ACTION_UNSET_ALL), + OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), + OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), + OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST), + OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), + OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot []"), ACTION_GET_COLOR), + OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot []"), ACTION_GET_COLORBOOL), OPT_GROUP(N_("Type")), OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), @@ -769,10 +769,6 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_builtin_config(); } - if (HAS_MULTI_BITS(actions)) { - error(_("only one action at a time")); - usage_builtin_config(); - } if (actions == 0) switch (argc) { case 1: actions = ACTION_GET; break; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 9b65d9eaf5..86dc70769a 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -2738,4 +2738,17 @@ test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err ' +test_expect_success 'negated mode causes failure' ' + test_must_fail git config --no-get 2>err && + grep "unknown option \`no-get${SQ}" err +' + +test_expect_success 'specifying multiple modes causes failure' ' + cat >expect <<-EOF && + error: options ${SQ}--get-all${SQ} and ${SQ}--get${SQ} cannot be used together + EOF + test_must_fail git config --get --get-all 2>err && + test_cmp expect err +' + test_done From patchwork Mon May 6 08:56:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655175 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFAF71422BB for ; Mon, 6 May 2024 08:56:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985782; cv=none; b=M0EZjA0+GFeFMGfxwL86BCmWOvN/XEY3pNnF+pi7pH3WH6hnwbqEfHfoplWKy58Pb9EQNazlQ1zDcFf20LR7tuEhDrJXNuJOAks6WdgwBIB0d9DDxHM5cVeo6ibndxk28PnjFYQudOlBLM7+sNIUju5fgWyRJfH5B77FYPh8//E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985782; c=relaxed/simple; bh=5lyJ6vVYyly7E8JLl4SWsIZUkBdmbHcJVcZsl8SWNso=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=KBuTRHPIwU7ZUmjShMhlSIv/vaZUqH7TPLkiPL0BCfJ3zxFZOQBHjk/zXVXUCsbm2mI3nZ7gN6IPNdHhDzrG4m3O1rm/sboiCNs1W7cJop5GJbsDMG+MBg6ZqidkHjzIXbHbsd8zqDP4yn1qjt0bXYBuIOBUsCco1nnRGdnJGBk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=odJoklYE; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=YeBJulHa; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="odJoklYE"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="YeBJulHa" Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailfhigh.west.internal (Postfix) with ESMTP id 8CAC718000C6; Mon, 6 May 2024 04:56:19 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Mon, 06 May 2024 04:56:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985779; x=1715072179; bh=O397vy0AYg /sm2vKfOCqFN++sdhBoXRPus8fWC+6kwQ=; b=odJoklYE3e5a4G9C46W5fdVKck gKVZdysx3aKQRm/OK/VCmqu6oonn2L8V+hviIHwjW6eIzMqhIeUgCIaM7qRL2JR+ 4MXjc+3+Oy+eq95hsSp0XoKURqk5YiM3iHHj4VFzwcKKHedVwDiW/fA2wyQKvWLv Al7g6ab/KKOySpqOCOCcllu632bqz3fJH5xCjyfWs7L66Onpn6keq2DuuwaQXHR7 iiDq0bYCUi3+BvvdLekdGr5NdmqE443JimMpebb5TnkrjIuALfgX3dR9Fn/zfMZ7 eD/92y87p3D3U6e3gann5PhIt7Wo1QXfbWBUN5lr5h44MSQa3HyC4KH4yhhw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985779; x=1715072179; bh=O397vy0AYg/sm2vKfOCqFN++sdhB oXRPus8fWC+6kwQ=; b=YeBJulHaHnm4tkeyWpG+/TRK62dtU8Qq0s2F+WB0DdNA k3NiLLdENiyNep6XWo4QkIzQcys5634W+EgXpnJBft6am+YG+8KQDV1RbrHd/uuc sLOGknnr6ZBUYimI1cK6WvHfxZrXi+BxJJLIDCwpk+9byXSItiZXgfzgrLZjPjqP 5BAliJ1EXd5nF8QxWfNryCKMdUfYMjNUO11kNqHgvsaT0yTKfi1t2gz0Ag2GysWH qXbhvBahO9ypuOuVbFj3jQjZ4/sqXYeu2Ian5nd22mRcuYAJwHF3D61dmWT7UlOi BP1iYx/akmbKJ6++3k0uloYR/Mb8L/k4T92EQdXrbQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:17 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 0de3fabd (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:11 +0000 (UTC) Date: Mon, 6 May 2024 10:56:14 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 05/14] builtin/config: pull out function to handle config location Message-ID: <4f90f206e70ca86f26a96c2db7cffd0e97a8c39a.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: There's quite a bunch of options to git-config(1) that allow the user to specify which config location to use when reading or writing config options. The logic to handle this is thus by necessity also quite involved. Pull it out into a separate function so that we can reuse it in subsequent commits which introduce proper subcommands. Signed-off-by: Patrick Steinhardt --- builtin/config.c | 133 ++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 8991533e08..8c7cd30cb4 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -623,68 +623,8 @@ static char *default_user_config(void) return strbuf_detach(&buf, NULL); } -static struct option builtin_config_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")), - OPT_GROUP(N_("Action")), - OPT_CMDMODE(0, "get", &actions, N_("get value: name []"), ACTION_GET), - OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key []"), ACTION_GET_ALL), - OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex []"), ACTION_GET_REGEXP), - OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), - OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value []"), ACTION_REPLACE_ALL), - OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), - OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name []"), ACTION_UNSET), - OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name []"), ACTION_UNSET_ALL), - OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), - OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), - OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST), - OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot []"), ACTION_GET_COLOR), - OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot []"), ACTION_GET_COLORBOOL), - OPT_GROUP(N_("Type")), - OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), - OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), - OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), - OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), - OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), - 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_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 (worktree, local, global, system, command)")), - OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), - OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), - OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), - OPT_END(), -}; - -static NORETURN void usage_builtin_config(void) +static void handle_config_location(const char *prefix) { - usage_with_options(builtin_config_usage, builtin_config_options); -} - -int cmd_config(int argc, const char **argv, const char *prefix) -{ - int nongit = !startup_info->have_repository; - char *value = NULL, *comment = NULL; - int flags = 0; - int ret = 0; - struct key_value_info default_kvi = KVI_INIT; - - given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); - - argc = parse_options(argc, argv, prefix, builtin_config_options, - builtin_config_usage, - PARSE_OPT_STOP_AT_NON_OPTION); - if (use_global_config + use_system_config + use_local_config + use_worktree_config + !!given_config_source.file + !!given_config_source.blob > 1) { @@ -692,14 +632,13 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_builtin_config(); } - if (nongit) { + if (!startup_info->have_repository) { if (use_local_config) die(_("--local can only be used inside a git repository")); if (given_config_source.blob) die(_("--blob can only be used inside a git repository")); if (use_worktree_config) die(_("--worktree can only be used inside a git repository")); - } if (given_config_source.file && @@ -753,10 +692,74 @@ int cmd_config(int argc, const char **argv, const char *prefix) config_options.respect_includes = !given_config_source.file; else config_options.respect_includes = respect_includes_opt; - if (!nongit) { + if (startup_info->have_repository) { config_options.commondir = get_git_common_dir(); config_options.git_dir = get_git_dir(); } +} + +static struct option builtin_config_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")), + OPT_GROUP(N_("Action")), + OPT_CMDMODE(0, "get", &actions, N_("get value: name []"), ACTION_GET), + OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key []"), ACTION_GET_ALL), + OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex []"), ACTION_GET_REGEXP), + OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH), + OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value []"), ACTION_REPLACE_ALL), + OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), + OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name []"), ACTION_UNSET), + OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name []"), ACTION_UNSET_ALL), + OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), + OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), + OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST), + OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), + OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot []"), ACTION_GET_COLOR), + OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot []"), ACTION_GET_COLORBOOL), + OPT_GROUP(N_("Type")), + OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), + OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), + OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), + OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), + OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), + 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_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 (worktree, local, global, system, command)")), + OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), + OPT_END(), +}; + +static NORETURN void usage_builtin_config(void) +{ + usage_with_options(builtin_config_usage, builtin_config_options); +} + +int cmd_config(int argc, const char **argv, const char *prefix) +{ + char *value = NULL, *comment = NULL; + int flags = 0; + int ret = 0; + struct key_value_info default_kvi = KVI_INIT; + + given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); + + argc = parse_options(argc, argv, prefix, builtin_config_options, + builtin_config_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + handle_config_location(prefix); if (end_nul) { term = '\0'; @@ -858,7 +861,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) char *config_file; check_argc(argc, 0, 0); - if (!given_config_source.file && nongit) + if (!given_config_source.file && !startup_info->have_repository) die(_("not in a git directory")); if (given_config_source.use_stdin) die(_("editing stdin is not supported")); From patchwork Mon May 6 08:56:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655176 Received: from wfout3-smtp.messagingengine.com (wfout3-smtp.messagingengine.com [64.147.123.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12F021422BB for ; Mon, 6 May 2024 08:56:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985786; cv=none; b=BtwTXcnOQZEiCPJdV8MpkJ+JVXbP92j3+Go/drqlv0Zvmt4yv3K/ooY+hRj/pscjXOcPr5NWUlKVCqXsXF2yoYOwIVNC7VoNRRX01AcnSFyPPyMs/Scc+ZPQSLGrBPo43PQWS9zt8c0HSjsxBrDWWrmNsN0xh5swKBnrTThx16c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985786; c=relaxed/simple; bh=DJ+V8hP5AeZpTcdTh/EZpVS3LhwVN+WUZv0PHto+cH8=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=eu3IEWldnaMC1FSZGMbWLvd1QEbjTBf6C/4ofQeTVRLeOxAOsTMEaY+VipouljMI4VeEpvwR4Axqavrd1hLXTu1A6AsstFDKskfYyFrnzwjKJP1YAfxxEVspABf2zguOSZgWGyS+P2PKmPFUVqjsxSBTFvR2AC0AYP8JuKmhIQ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=rzXZG38C; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=ACtEibIk; arc=none smtp.client-ip=64.147.123.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="rzXZG38C"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="ACtEibIk" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfout.west.internal (Postfix) with ESMTP id 88BAE1C000AE; Mon, 6 May 2024 04:56:23 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 06 May 2024 04:56:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985783; x=1715072183; bh=L0ypZ1GleS baz+2Ny9iAiNCBjilLztBJOtPPfr82U/U=; b=rzXZG38CSGhU1TjefVyplAf/g2 mgmhmrsoyZaPUIoym3jyJKFDfkwL8NRwVsi+ZHQ/2/M5Jeq3w3l4UzSoI2iAA5tl 2mr7GxFTbZprI06h4HFvCsEnIFTJtE7H5nQBKTyWbURkPK02d7H6ALyea9KeSVe2 D0ijaYW7mO7lQJ7hd5bT1Ggodd9URkAaLbGSIkSnb3DHvmH70tv2iwstlnCq3EJK zEA//2OlwRhHdDES4AJWXxKI8v4XSpKFKZwQ7s6hODBuvY1PuG6RjcMrtrPcU7ZW +WmVwX1Qwjj1htplVupp76EjHC5Eu1GurrebMeEQqAxofsVUBFc4WBN2+MhA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985783; x=1715072183; bh=L0ypZ1GleSbaz+2Ny9iAiNCBjilL ztBJOtPPfr82U/U=; b=ACtEibIklBAmRsORFvXHgXEscwf43oUIOXiUjyj8broU luAzgPCg9b+T1iowMuvPVT3PWMPQnRYgul5c+Q+aWNDdVgFX6Jh7U5B9SjA9eB0A E2GvrQm5cdi/c7anDJNTVj4QdidYcYBzMJJtXdveJmCRTxOE+zd/fS2J8VOp2uuC pv3Lj3ZqRBteWd7QknqkQx9BRTM7bqjUHZBW0dwNYS4UFB7xmJtFLllD7L6nP/Cw FeowxFrpquXKODyiz4vQBJ+5A8gDI9kcaTQupmZZpmIDv5kFFMa5+uBreCwf42nd nSYlVjnW4/0UKmM/OmgkmyxyxR2UN/QTLngMyscY0A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:21 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 2b30051b (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:16 +0000 (UTC) Date: Mon, 6 May 2024 10:56:19 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 06/14] builtin/config: pull out function to handle `--null` Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Pull out function to handle the `--null` option, which we are about to reuse in subsequent commits. Signed-off-by: Patrick Steinhardt --- builtin/config.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 8c7cd30cb4..59877065f8 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -698,6 +698,14 @@ static void handle_config_location(const char *prefix) } } +static void handle_nul(void) { + if (end_nul) { + term = '\0'; + delim = '\n'; + key_delim = '\n'; + } +} + static struct option builtin_config_options[] = { OPT_GROUP(N_("Config file location")), OPT_BOOL(0, "global", &use_global_config, N_("use global config file")), @@ -760,12 +768,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) PARSE_OPT_STOP_AT_NON_OPTION); handle_config_location(prefix); - - if (end_nul) { - term = '\0'; - delim = '\n'; - key_delim = '\n'; - } + handle_nul(); if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) { error(_("--get-color and variable type are incoherent")); From patchwork Mon May 6 08:56:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655177 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EC041419A1 for ; Mon, 6 May 2024 08:56:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985792; cv=none; b=CZG7gwQOJTrQ+1Ku9JvAM7DC5jwUnm+Exv+1AaMaIktaEFQO3svpn+yh/r6wFeO8syUPJor0yrSmWfEb3SHA3FU2BhGUvUvhYyR5qmrLeBX1GbeYzj5yzAGyM8Q0zSLsOj6juvlEKDP5hZjxOyXu0scnPYApw2xChOz7FPR6AJE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985792; c=relaxed/simple; bh=ijas9RwWupzfS6QMgNPhae+AnVdMvYwpMkC7zpLg1VQ=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=RcacLKyKR72kCEyx51pgRisW3MJOjmQFOixRsFBAsYKlLBds5HwMVBbLfhoE6uCZCE8iH4k6OQp2Ksfi/nh9nm3dp+LFmpaIN8CjJ0KIZ2d66t0vfcXLTyjMlNPb6+sNFLMTjhpiZtSDDAYHY0SQtNKMjk1sepCVJMmRwjWKSX8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=TlMef1Ga; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=KtW6st36; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="TlMef1Ga"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="KtW6st36" Received: from compute7.internal (compute7.nyi.internal [10.202.2.48]) by mailfhigh.west.internal (Postfix) with ESMTP id C2C4718000CC; Mon, 6 May 2024 04:56:28 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Mon, 06 May 2024 04:56:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985788; x=1715072188; bh=eXIC0bNRSM OWzK32yTjOP0q20V6BM+SYx7NrKBKP4X8=; b=TlMef1GazcWLG1y1PkhJEF/FMX z+nOjFqq1ADrOReUFqM3vldX9yMOAs17jRDyGRWPpjlN7G865OZGvrC/7Kpv3qDD x68ejPVv3e9Uc0G/9dtK8oFpJ33AmCntlJq/wMAHbd2uOueFOLQsw0MAalmrlgeR bTTmYH/D0jqWD5wdhiyj19VGCb1tiUnA+5t052oY2h6xsJ5Cvv0AizV3q1sMxAal F0djn2KjQaxZ/s+rWcN7h7YeNBpc020J8QM/PHbaWI6/CyYTv3ITLdgj2myV7mys 6bFBz4j8rQqsDbHWeCpMAa3U1U2IjEPEB1aulhv7gTgHzZuv3NZBAwLGwOBg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985788; x=1715072188; bh=eXIC0bNRSMOWzK32yTjOP0q20V6B M+SYx7NrKBKP4X8=; b=KtW6st36UmHNunNFxK5VKlJK3gzb4wcmf/UZB1hRXqEl NZqqEgyZiHSdA6wEYMUrFbaaBV0Gbw//e1FZ6eDHkJJsaRwWFF81DoJmYfMAgup8 KU7fyCZzVzlt/9ZqmR7jWdEPZhAibD32sLmzV5LvbS0jV/M7Hi9dbh+TMLK0mwew n5MDaiII6gv+RdTIelRg69FMOGc3GwyTSN/SYKNMIjJmPr6uaiAqMVmktgOW7Po9 CzaTMXnvqseJcpWb3yV7b7QgNjQv9kRVgdt5J2ZUKjibddS9D2OOMyJwIDZ+MseD che041bhNvsM2z0w8diSHXJawR7gJyLcsEzS3WMGnQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:26 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 1df4064c (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:21 +0000 (UTC) Date: Mon, 6 May 2024 10:56:24 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 07/14] builtin/config: introduce "list" subcommand Message-ID: <1df76a99704fec6d5306db73744007278e97157b.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: While git-config(1) has several modes, those modes are not exposed with subcommands but instead by specifying action flags like `--unset` or `--list`. This user interface is not really in line with how our more modern commands work, where it is a lot more customary to say e.g. `git remote list`. Furthermore, to add to the confusion, git-config(1) also allows the user to request modes implicitly by just specifying the correct number of arguments. Thus, `git config foo.bar` will retrieve the value of "foo.bar" while `git config foo.bar baz` will set it to "baz". Overall, this makes for a confusing interface that could really use a makeover. It hurts discoverability of what you can do with git-config(1) and is comparatively easy to get wrong. Converting the command to have subcommands instead would go a long way to help address these issues. One concern in this context is backwards compatibility. Luckily, we can introduce subcommands without breaking backwards compatibility at all. This is because all the implicit modes of git-config(1) require that the first argument is a properly formatted config key. And as config keys _must_ have a dot in their name, any value without a dot would have been discarded by git-config(1) previous to this change. Thus, given that none of the subcommands do have a dot, they are unambiguous. Introduce the first such new subcommand, which is "git config list". To retain backwards compatibility we only conditionally use subcommands and will fall back to the old syntax in case no subcommand was detected. This should help to transition to the new-style syntax until we eventually deprecate and remove the old-style syntax. Note that the way we handle this we're duplicating some functionality across old and new syntax. While this isn't pretty, it helps us to ensure that there really is no change in behaviour for the old syntax. Amend tests such that we run them both with old and new style syntax. As tests are now run twice, state from the first run may be still be around in the second run and thus cause tests to fail. Add cleanup logic as required to fix such tests. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 26 ++++++--- builtin/config.c | 90 ++++++++++++++++++++++++---- t/t1300-config.sh | 110 +++++++++++++++++++++-------------- 3 files changed, 162 insertions(+), 64 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index ac61113fcc..c83c97cb7e 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -9,6 +9,7 @@ git-config - Get and set repository or global options SYNOPSIS -------- [verse] +'git config list' [] [] [--includes] 'git config' [] [--type=] [--comment=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] 'git config' [] [--type=] [--comment=] --add 'git config' [] [--type=] [--comment=] [--fixed-value] --replace-all [] @@ -20,7 +21,6 @@ SYNOPSIS 'git config' [] [--fixed-value] --unset-all [] 'git config' [] --rename-section 'git config' [] --remove-section -'git config' [] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list 'git config' [] --get-color [] 'git config' [] --get-colorbool [] 'git config' [] -e | --edit @@ -74,6 +74,12 @@ On success, the command returns the exit code 0. A list of all available configuration variables can be obtained using the `git help --config` command. +COMMANDS +-------- + +list:: + List all variables set in config file, along with their values. + [[OPTIONS]] OPTIONS ------- @@ -190,10 +196,6 @@ See also <>. --unset-all:: Remove all lines matching the key from config file. --l:: ---list:: - List all variables set in config file, along with their values. - --fixed-value:: When used with the `value-pattern` argument, treat `value-pattern` as an exact string instead of a regular expression. This will restrict @@ -248,7 +250,7 @@ Valid ``'s include: contain line breaks. --name-only:: - Output only the names of config variables for `--list` or + Output only the names of config variables for `list` or `--get-regexp`. --show-origin:: @@ -300,10 +302,20 @@ Valid ``'s include: When using `--get`, and the requested variable is not found, behave as if were the value assigned to that variable. +DEPRECATED MODES +---------------- + +The following modes have been deprecated in favor of subcommands. It is +recommended to migrate to the new syntax. + +-l:: +--list:: + Replaced by `git config list`. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when -using `--list` or any of the `--get-*` which may return multiple results. +using `list` or any of the `--get-*` which may return multiple results. The default is to use a pager. [[FILES]] diff --git a/builtin/config.c b/builtin/config.c index 59877065f8..f89ddce8da 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -16,10 +16,16 @@ #include "worktree.h" static const char *const builtin_config_usage[] = { + N_("git config list [] [] [--includes]"), N_("git config []"), NULL }; +static const char *const builtin_config_list_usage[] = { + N_("git config list [] [] [--includes]"), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -33,6 +39,7 @@ static char delim = '='; static char key_delim = ' '; static char term = '\n'; +static parse_opt_subcommand_fn *subcommand; static int use_global_config, use_system_config, use_local_config; static int use_worktree_config; static struct git_config_source given_config_source; @@ -706,14 +713,24 @@ 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_DISPLAY_OPTIONS \ + OPT_GROUP(N_("Display options")), \ + 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, "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)")) + static struct option builtin_config_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")), + CONFIG_LOCATION_OPTIONS, OPT_GROUP(N_("Action")), OPT_CMDMODE(0, "get", &actions, N_("get value: name []"), ACTION_GET), OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key []"), ACTION_GET_ALL), @@ -737,15 +754,12 @@ static struct option builtin_config_options[] = { OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), 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), + CONFIG_DISPLAY_OPTIONS, OPT_GROUP(N_("Other")), - 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 (worktree, local, global, system, command)")), OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), OPT_END(), }; @@ -754,6 +768,42 @@ static NORETURN void usage_builtin_config(void) usage_with_options(builtin_config_usage, builtin_config_options); } +static int cmd_config_list(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + CONFIG_DISPLAY_OPTIONS, + OPT_GROUP(N_("Other")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0); + check_argc(argc, 0, 0); + + handle_config_location(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) + die_errno(_("unable to read config file '%s'"), + given_config_source.file); + else + die(_("error processing config file(s)")); + } + + return 0; +} + +static struct option builtin_subcommand_options[] = { + OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), + OPT_END(), +}; + int cmd_config(int argc, const char **argv, const char *prefix) { char *value = NULL, *comment = NULL; @@ -763,6 +813,22 @@ int cmd_config(int argc, const char **argv, const char *prefix) 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 + * has been specified. If so, we re-parse it a second time, but this + * time we drop KEEP_ARGV0. This is so that we don't munge the command + * line in case no subcommand was given, which would otherwise confuse + * us when parsing the legacy-style modes that don't use subcommands. + */ + argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_NO_INTERNAL_HELP|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT); + if (subcommand) { + argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_NO_INTERNAL_HELP|PARSE_OPT_KEEP_UNKNOWN_OPT); + return subcommand(argc, argv, prefix); + } + argc = parse_options(argc, argv, prefix, builtin_config_options, builtin_config_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 86dc70769a..f77d2f7847 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -11,6 +11,20 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +for mode in legacy subcommands +do + +case "$mode" in +legacy) + mode_prefix="--" + ;; +subcommands) + mode_prefix="" + ;; +*) + BUG "unknown mode $mode";; +esac + test_expect_success 'setup whitespace config' ' sed -e "s/^|//" \ -e "s/[$]$//" \ @@ -460,11 +474,11 @@ version.1.2.3eX.alpha=beta EOF test_expect_success 'working --list' ' - git config --list > output && + git config ${mode_prefix}list > output && test_cmp expect output ' test_expect_success '--list without repo produces empty output' ' - git --git-dir=nonexistent config --list >output && + git --git-dir=nonexistent config ${mode_prefix}list >output && test_must_be_empty output ' @@ -476,7 +490,7 @@ version.1.2.3eX.alpha EOF test_expect_success '--name-only --list' ' - git config --name-only --list >output && + git config ${mode_prefix}list --name-only >output && test_cmp expect output ' @@ -614,17 +628,17 @@ ein.bahn=strasse EOF test_expect_success 'alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config --list >output && + GIT_CONFIG=other-config git config ${mode_prefix}list >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file)' ' - git config --file other-config --list >output && + git config ${mode_prefix}list --file other-config >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file=-)' ' - git config --file - --list output && + git config ${mode_prefix}list --file - output && test_cmp expect output ' @@ -637,6 +651,7 @@ test_expect_success 'editing stdin is an error' ' ' test_expect_success 'refer config from subdirectory' ' + test_when_finished "rm -r x" && mkdir x && test_cmp_config -C x strasse --file=../other-config --get ein.bahn ' @@ -847,7 +862,7 @@ test_expect_success 'line number is reported correctly' ' ' test_expect_success 'invalid stdin config' ' - echo "[broken" | test_must_fail git config --list --file - >output 2>&1 && + echo "[broken" | test_must_fail git config ${mode_prefix}list --file - >output 2>&1 && test_grep "bad config line 1 in standard input" output ' @@ -1139,7 +1154,7 @@ section.quotecont=cont;inued EOF test_expect_success 'value continued on next line' ' - git config --list > result && + git config ${mode_prefix}list > result && test_cmp expect result ' @@ -1163,7 +1178,7 @@ Qsection.sub=section.val4 Qsection.sub=section.val5Q EOF test_expect_success '--null --list' ' - git config --null --list >result.raw && + git config ${mode_prefix}list --null >result.raw && nul_to_q result && echo >>result && test_cmp expect result @@ -1198,6 +1213,7 @@ test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' test_expect_success SYMLINKS 'symlinked configuration' ' + test_when_finished "rm myconfig" && ln -s notyet myconfig && git config --file=myconfig test.frotz nitfol && test -h myconfig && @@ -1218,10 +1234,11 @@ test_expect_success SYMLINKS 'symlinked configuration' ' ' test_expect_success SYMLINKS 'symlink to nonexistent configuration' ' + test_when_finished "rm linktonada linktolinktonada" && ln -s doesnotexist linktonada && ln -s linktonada linktolinktonada && - test_must_fail git config --file=linktonada --list && - test_must_fail git config --file=linktolinktonada --list + test_must_fail git config ${mode_prefix}list --file=linktonada && + test_must_fail git config ${mode_prefix}list --file=linktolinktonada ' test_expect_success 'check split_cmdline return' ' @@ -1478,7 +1495,7 @@ do done test_expect_success 'git -c is not confused by empty environment' ' - GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list + GIT_CONFIG_PARAMETERS="" git -c x.one=1 config ${mode_prefix}list ' test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' ' @@ -1669,31 +1686,31 @@ test_expect_success 'git config ignores pairs with empty count' ' ' test_expect_success 'git config fails with invalid count' ' - test_must_fail env GIT_CONFIG_COUNT=10a git config --list 2>error && + test_must_fail env GIT_CONFIG_COUNT=10a git config ${mode_prefix}list 2>error && test_grep "bogus count" error && - test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config --list 2>error && + test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config ${mode_prefix}list 2>error && test_grep "too many entries" error ' test_expect_success 'git config fails with missing config key' ' test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_VALUE_0="value" \ - git config --list 2>error && + git config ${mode_prefix}list 2>error && test_grep "missing config key" error ' test_expect_success 'git config fails with missing config value' ' test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0="pair.one" \ - git config --list 2>error && + git config ${mode_prefix}list 2>error && test_grep "missing config value" error ' test_expect_success 'git config fails with invalid config pair key' ' test_must_fail env GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0= GIT_CONFIG_VALUE_0=value \ - git config --list && + git config ${mode_prefix}list && test_must_fail env GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0=missing-section GIT_CONFIG_VALUE_0=value \ - git config --list + git config ${mode_prefix}list ' test_expect_success 'environment overrides config file' ' @@ -1733,7 +1750,7 @@ test_expect_success 'git config --edit works' ' git config -f tmp test.value no && echo test.value=yes >expect && GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit && - git config -f tmp --list >actual && + git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' @@ -1742,7 +1759,7 @@ test_expect_success 'git config --edit respects core.editor' ' echo test.value=yes >expect && test_config core.editor "echo [test]value=yes >" && git config -f tmp --edit && - git config -f tmp --list >actual && + git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' @@ -2093,7 +2110,7 @@ test_expect_success '--show-origin with --list' ' command line: user.cmdline=true EOF GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.environ GIT_CONFIG_VALUE_0=true\ - git -c user.cmdline=true config --list --show-origin >output && + git -c user.cmdline=true config ${mode_prefix}list --show-origin >output && test_cmp expect output ' @@ -2110,7 +2127,7 @@ test_expect_success '--show-origin with --list --null' ' includeQcommand line:Quser.cmdline trueQ EOF - git -c user.cmdline=true config --null --list --show-origin >output.raw && + git -c user.cmdline=true config ${mode_prefix}list --null --show-origin >output.raw && nul_to_q output && # The here-doc above adds a newline that the --null output would not # include. Add it here to make the two comparable. @@ -2124,7 +2141,7 @@ test_expect_success '--show-origin with single file' ' file:.git/config user.override=local file:.git/config include.path=../include/relative.include EOF - git config --local --list --show-origin >output && + git config ${mode_prefix}list --local --show-origin >output && test_cmp expect output ' @@ -2162,7 +2179,7 @@ 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 "$WEIRDLY_NAMED_FILE" --show-origin --list >output && + git config ${mode_prefix}list --file "$WEIRDLY_NAMED_FILE" --show-origin >output && test_cmp expect output ' @@ -2170,7 +2187,7 @@ test_expect_success '--show-origin stdin' ' cat >expect <<-\EOF && standard input: user.custom=true EOF - git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output && + git config ${mode_prefix}list --file - --show-origin <"$CUSTOM_CONFIG_FILE" >output && test_cmp expect output ' @@ -2197,7 +2214,7 @@ test_expect_success '--show-origin blob' ' cat >expect <<-EOF && blob:$blob user.custom=true EOF - git config --blob=$blob --show-origin --list >output && + git config ${mode_prefix}list --blob=$blob --show-origin >output && test_cmp expect output ) ' @@ -2213,7 +2230,7 @@ test_expect_success '--show-origin blob ref' ' cp "$CUSTOM_CONFIG_FILE" custom.conf && git add custom.conf && git commit -m "new config file" && - git config --blob=main:custom.conf --show-origin --list >output && + git config ${mode_prefix}list --blob=main:custom.conf --show-origin >output && test_cmp expect output ) ' @@ -2239,13 +2256,14 @@ test_expect_success '--show-scope with --list' ' worktree user.worktree=true command user.cmdline=true EOF + test_when_finished "git worktree remove wt1" && git worktree add wt1 && # We need these to test for worktree scope, but outside of this # test, this is just noise test_config core.repositoryformatversion 1 && test_config extensions.worktreeConfig true && git config --worktree user.worktree true && - git -c user.cmdline=true config --list --show-scope >output && + git -c user.cmdline=true config ${mode_prefix}list --show-scope >output && test_cmp expect output ' @@ -2254,7 +2272,7 @@ test_expect_success !MINGW '--show-scope with --blob' ' cat >expect <<-EOF && command user.custom=true EOF - git config --blob=$blob --show-scope --list >output && + git config ${mode_prefix}list --blob=$blob --show-scope >output && test_cmp expect output ' @@ -2264,7 +2282,7 @@ test_expect_success '--show-scope with --local' ' local user.override=local local include.path=../include/relative.include EOF - git config --local --list --show-scope >output && + git config ${mode_prefix}list --local --show-scope >output && test_cmp expect output ' @@ -2288,7 +2306,7 @@ test_expect_success '--show-scope with --show-origin' ' 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 && + git -c user.cmdline=true config ${mode_prefix}list --show-origin --show-scope >output && test_cmp expect output ' @@ -2329,7 +2347,7 @@ test_expect_success 'override global and system config' ' global home.config=true local local.config=true EOF - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output && cat >expect <<-EOF && @@ -2338,20 +2356,20 @@ test_expect_success 'override global and system config' ' local local.config=true EOF GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=custom-system-config GIT_CONFIG_GLOBAL=custom-global-config \ - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output && cat >expect <<-EOF && local local.config=true EOF GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_GLOBAL=/dev/null \ - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output ' test_expect_success 'override global and system config with missing file' ' - test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list && - test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list && + test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config ${mode_prefix}list --global && + test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config ${mode_prefix}list --system && GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version ' @@ -2478,7 +2496,7 @@ test_expect_success 'set all config with value-pattern' ' # no match => add new entry cp initial config && git config --file=config abc.key two a+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2491,7 +2509,7 @@ test_expect_success 'set all config with value-pattern' ' # multiple values, no match => add git config --file=config abc.key three a+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2501,7 +2519,7 @@ test_expect_success 'set all config with value-pattern' ' # single match => replace git config --file=config abc.key four h+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2516,7 +2534,7 @@ test_expect_success '--replace-all and value-pattern' ' git config --file=config --add abc.key two && git config --file=config --add abc.key three && git config --file=config --replace-all abc.key four "o+" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=four abc.key=three @@ -2534,7 +2552,7 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && test_must_fail git config --file=config --fixed-value --rename-section dev null && test_must_fail git config --file=config --fixed-value --remove-section dev && - test_must_fail git config --file=config --fixed-value --list && + test_must_fail git config ${mode_prefix}list --file=config --fixed-value && test_must_fail git config --file=config --fixed-value --get-color dev.null && test_must_fail git config --file=config --fixed-value --get-colorbool dev.null && @@ -2555,7 +2573,7 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && git config --file=config fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=$META fixed.test=bogus @@ -2564,7 +2582,7 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && git config --file=config --fixed-value fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && fixed.test=bogus EOF @@ -2582,7 +2600,7 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && git config --file=config --replace-all fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=$META fixed.test=bogus @@ -2590,7 +2608,7 @@ test_expect_success '--fixed-value uses exact string matching' ' test_cmp expect actual && git config --file=config --fixed-value --replace-all fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=bogus fixed.test=bogus @@ -2751,4 +2769,6 @@ test_expect_success 'specifying multiple modes causes failure' ' test_cmp expect err ' +done + test_done From patchwork Mon May 6 08:56:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655178 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D5A671422AA for ; Mon, 6 May 2024 08:56:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985797; cv=none; b=cxPAaXcsRyRy8lTwAPfCjPQGqhmygAhv6O0ALrgQQ+8rytMWvy2M9Bp/6PNOnpJA4m8trrhoBsPk8uexUPr5ZPWsNT2cwgUpHuKmjSDj6F6/QXnYGRaKTaEuSE+n9fOyWkBLfQZ+riSf3Tu5CFCneiAufeU0g1Dbn5QMcrsle1I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985797; c=relaxed/simple; bh=8SRpCej9kfBOp5tqGMidiX0eBLhHuttc0W2Z9/D8hPc=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=Gmy98KZBt/99jv++xG7BPkZif47e0oK8oh2lDyoT7mAIOZr0qj3SLxVUzEDVtKW8jFzryebDvDpy4VvQ1kOBfj9qVi6kBGssb/FoWjvwRRozA2ozExzKboKcTapFXaVapwUnY2m1CpBExjCEvlsqfeZx9ZaTOIHMeTYxUBXTh6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=kGbhylaj; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=bAyVqmEj; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="kGbhylaj"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="bAyVqmEj" Received: from compute7.internal (compute7.nyi.internal [10.202.2.48]) by mailfhigh.west.internal (Postfix) with ESMTP id CE23B1800087; Mon, 6 May 2024 04:56:33 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Mon, 06 May 2024 04:56:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985793; x=1715072193; bh=xXP5iY8UIY nJ/O0BLs/CdhLjSPJHn1JEmsJqzxl6qmE=; b=kGbhylaj0A6yOkC+SK6A+J13wi oSuSn0gF/4T32WE3UOATVxZ8KErTOibfhy8PY1/n6t7VbM1YX5D2ALlMCF/zxv4O Yi5dGIa/ok2XverOuAx5pIfC8meJA4lZ1w46xoXqfZLBWDMld51KSaI6qMM1nQyL tEtSXGWkUD+arWXk1aGXXtVCOsYzBeHGWOqAyjQk+qbZ0xWrlzaelG02xTZPcMKv zO9CMS8pYSJj5aQ1JASKwaALdUYkUESDL/KZ5JlmFZVpCfQJdRxJcpF771ZNeTm/ yAwWO85ZOz9safGhEUkFL0HfDseEsQtmKDupsD9yD5FiwSLWBrXG5VWVpgeQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985793; x=1715072193; bh=xXP5iY8UIYnJ/O0BLs/CdhLjSPJH n1JEmsJqzxl6qmE=; b=bAyVqmEjpVwg8ZVXgb6nswPQnK0j1Da2GKKeG0bwQZ4b J9h7w0Qjx9/f52127uBjCfGB6TqP3/Awp36SQBTyyKIGcj+G9zUNtSHAJ5LxUNQ7 5LKeHCTCQiYWzrBijpNv3edtZGEs93SltP6gvXh2RCZJAxZ4ZYKqxN9yP18UVSbR 3BjmNIo+aPbfv7znxRpQhq7AwWhtfYrqNr67bA29cfWpXpK3X/vR4W7gQ2CVfWEz 1RxQ/YHSS1/uAEQKJHdqNhQQtxFYK1m3Br6rjhE7EsUDpojplXxgtUG1f/MkGqmK cCJS0bGZP5hQ8LSUi9jz4qQ36rGCKtirLzs9h0MdTw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne hushgvrhcuihhnuchlihhnkhculdeitddmnecujfgurhepfffhvfevuffkfhggtggujges ghdtreertddtvdenucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceoph hssehpkhhsrdhimheqnecuggftrfgrthhtvghrnhepudfgledtuedtvdfhlefhfeefjefg gfejvdehhfekgeevleelhfehieeiffdtgfdunecuffhomhgrihhnpeguihhffhdrnhgvfi dpkhgvrhhnvghlrdhorhhgpdgvgigrmhhplhgvrdgtohhmpdgvgigrmhhplhgvrdhorhhg necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:31 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 40bb0794 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:26 +0000 (UTC) Date: Mon, 6 May 2024 10:56:29 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 08/14] builtin/config: introduce "get" subcommand Message-ID: <29676b81e0151e2982326663f8b64e2a70bec0f8.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "get" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 93 ++++++++++++------------- builtin/config.c | 69 +++++++++++++++--- t/t1300-config.sh | 131 ++++++++++++++++++++++++----------- 3 files changed, 194 insertions(+), 99 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index c83c97cb7e..d0878663db 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -10,18 +10,14 @@ SYNOPSIS -------- [verse] 'git config list' [] [] [--includes] +'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] 'git config' [] [--type=] [--comment=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] 'git config' [] [--type=] [--comment=] --add 'git config' [] [--type=] [--comment=] [--fixed-value] --replace-all [] -'git config' [] [--type=] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get [] -'git config' [] [--type=] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all [] -'git config' [] [--type=] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp [] -'git config' [] [--type=] [-z|--null] --get-urlmatch 'git config' [] [--fixed-value] --unset [] 'git config' [] [--fixed-value] --unset-all [] 'git config' [] --rename-section 'git config' [] --remove-section -'git config' [] --get-color [] 'git config' [] --get-colorbool [] 'git config' [] -e | --edit @@ -80,6 +76,12 @@ COMMANDS list:: List all variables set in config file, along with their values. +get:: + Emits the value of the specified key. If key is present multiple times + in the configuration, emits the last value. If `--all` is specified, + emits all values associated with key. Returns error code 1 if key is + not present. + [[OPTIONS]] OPTIONS ------- @@ -105,22 +107,16 @@ OPTIONS not contain linefeed characters (no multi-line comments are permitted). ---get:: - Get the value for a given key (optionally filtered by a regex - matching the value). Returns error code 1 if the key was not - found and the last value if multiple key values were found. - ---get-all:: - Like get, but returns all values for a multi-valued key. +--all:: + With `get`, return all values for a multi-valued key. ---get-regexp:: - Like --get-all, but interprets the name as a regular expression and - writes out the key names. Regular expression matching is currently - case-sensitive and done against a canonicalized version of the key - in which section and variable names are lowercased, but subsection - names are not. +---regexp:: + With `get`, interpret the name as a regular expression. Regular + expression matching is currently case-sensitive and done against a + canonicalized version of the key in which section and variable names + are lowercased, but subsection names are not. ---get-urlmatch :: +--url=:: When given a two-part as
., the value for
.. whose part matches the best to the given URL is returned (if no such key exists, the value for @@ -251,7 +247,7 @@ Valid ``'s include: --name-only:: Output only the names of config variables for `list` or - `--get-regexp`. + `get`. --show-origin:: Augment the output of all queried config options with the @@ -275,17 +271,6 @@ Valid ``'s include: When the color setting for `name` is undefined, the command uses `color.ui` as fallback. ---get-color []:: - - Find the color configured for `name` (e.g. `color.diff.new`) and - output it as the ANSI color escape sequence to the standard - output. The optional `default` parameter is used instead, if - there is no color configured for `name`. -+ -`--type=color [--default=]` is preferred over `--get-color` -(but note that `--get-color` will omit the trailing newline printed by -`--type=color`). - -e:: --edit:: Opens an editor to modify the specified config file; either @@ -299,7 +284,7 @@ Valid ``'s include: config files. --default :: - When using `--get`, and the requested variable is not found, behave as if + When using `get`, and the requested variable is not found, behave as if were the value assigned to that variable. DEPRECATED MODES @@ -308,15 +293,33 @@ DEPRECATED MODES The following modes have been deprecated in favor of subcommands. It is recommended to migrate to the new syntax. +'git config ':: + Replaced by `git config get `. + -l:: --list:: Replaced by `git config list`. +--get []:: + Replaced by `git config get [--value=] `. + +--get-all []:: + Replaced by `git config get [--value=] --all --show-names `. + +--get-regexp :: + Replaced by `git config get --all --show-names --regexp `. + +--get-urlmatch :: + Replaced by `git config get --all --show-names --url= `. + +--get-color []:: + Replaced by `git config get --type=color [--default=] `. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when -using `list` or any of the `--get-*` which may return multiple results. -The default is to use a pager. +using `list` or `get` which may return multiple results. The default is to use +a pager. [[FILES]] FILES @@ -519,25 +522,19 @@ you have to provide a regex matching the value of exactly one line. To query the value for a given key, do ------------ -% git config --get core.filemode ------------- - -or - ------------- -% git config core.filemode +% git config get core.filemode ------------ or, to query a multivar: ------------ -% git config --get core.gitproxy "for kernel.org$" +% git config get --value="for kernel.org$" core.gitproxy ------------ If you want to know all the values for a multivar, do: ------------ -% git config --get-all core.gitproxy +% git config get --all --show-names core.gitproxy ------------ If you like to live dangerously, you can replace *all* core.gitproxy by a @@ -571,8 +568,8 @@ script: ------------ #!/bin/sh -WS=$(git config --get-color color.diff.whitespace "blue reverse") -RESET=$(git config --get-color "" "reset") +WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace) +RESET=$(git config get --type=color --default="reset" "") echo "${WS}your whitespace color or blue reverse${RESET}" ------------ @@ -580,11 +577,11 @@ For URLs in `https://weak.example.com`, `http.sslVerify` is set to false, while it is set to `true` for all others: ------------ -% git config --type=bool --get-urlmatch http.sslverify https://good.example.com +% git config get --type=bool --url=https://good.example.com http.sslverify true -% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com +% git config get --type=bool --url=https://weak.example.com http.sslverify false -% git config --get-urlmatch http https://weak.example.com +% git config get --url=https://weak.example.com http http.cookieFile /tmp/cookie.txt http.sslverify false ------------ diff --git a/builtin/config.c b/builtin/config.c index f89ddce8da..9e7ae49c02 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -17,7 +17,7 @@ static const char *const builtin_config_usage[] = { N_("git config list [] [] [--includes]"), - N_("git config []"), + N_("git config get [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] "), NULL }; @@ -26,6 +26,11 @@ static const char *const builtin_config_list_usage[] = { NULL }; +static const char *const builtin_config_get_usage[] = { + N_("git config get [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] "), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -722,6 +727,16 @@ static void handle_nul(void) { 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), \ + OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \ + OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \ + OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \ + OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \ + 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) + #define CONFIG_DISPLAY_OPTIONS \ OPT_GROUP(N_("Display options")), \ OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), \ @@ -746,14 +761,7 @@ static struct option builtin_config_options[] = { OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot []"), ACTION_GET_COLOR), OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot []"), ACTION_GET_COLORBOOL), - OPT_GROUP(N_("Type")), - OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), - OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), - OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), - OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), - OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), - 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), + CONFIG_TYPE_OPTIONS, CONFIG_DISPLAY_OPTIONS, OPT_GROUP(N_("Other")), OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), @@ -799,8 +807,51 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix) return 0; } +static int cmd_config_get(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL, *url = NULL; + int flags = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + CONFIG_TYPE_OPTIONS, + OPT_GROUP(N_("Filter options")), + OPT_BOOL(0, "all", &do_all, N_("return all values for multi-valued config options")), + OPT_BOOL(0, "regexp", &use_key_regexp, N_("interpret the name as a regular expression")), + OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")), + CONFIG_DISPLAY_OPTIONS, + OPT_BOOL(0, "show-names", &show_keys, N_("show config keys in addition to their values")), + OPT_GROUP(N_("Other")), + OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")), + OPT_STRING(0, "default", &default_value, N_("value"), N_("use default value when missing entry")), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_argc(argc, 1, 1); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with 'value-pattern'")); + if (default_value && (do_all || url)) + die(_("--default= cannot be used with --all or --url=")); + if (url && (do_all || use_key_regexp || value_pattern)) + die(_("--url= cannot be used with --all, --regexp or --value")); + + handle_config_location(prefix); + handle_nul(); + + setup_auto_pager("config", 1); + + if (url) + return get_urlmatch(argv[0], url); + return get_value(argv[0], value_pattern, flags); +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), + OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), OPT_END(), }; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index f77d2f7847..7ce13ed6cd 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -17,9 +17,15 @@ do case "$mode" in legacy) mode_prefix="--" + mode_get="" + mode_get_all="--get-all" + mode_get_regexp="--get-regexp" ;; subcommands) mode_prefix="" + mode_get="get" + mode_get_all="get --all" + mode_get_regexp="get --regexp --all --show-names" ;; *) BUG "unknown mode $mode";; @@ -398,7 +404,7 @@ test_expect_success 'multi-valued get-all returns all' ' wow wow2 for me EOF - git config --get-all nextsection.nonewline >actual && + git config ${mode_get_all} nextsection.nonewline >actual && test_cmp expect actual ' @@ -500,7 +506,7 @@ nextsection.nonewline wow2 for me EOF test_expect_success '--get-regexp' ' - git config --get-regexp in >output && + git config ${mode_get_regexp} in >output && test_cmp expect output ' @@ -510,7 +516,7 @@ nextsection.nonewline EOF test_expect_success '--name-only --get-regexp' ' - git config --name-only --get-regexp in >output && + git config ${mode_get_regexp} --name-only in >output && test_cmp expect output ' @@ -521,7 +527,7 @@ EOF test_expect_success '--add' ' git config --add nextsection.nonewline "wow4 for you" && - git config --get-all nextsection.nonewline > output && + git config ${mode_get_all} nextsection.nonewline > output && test_cmp expect output ' @@ -543,21 +549,21 @@ test_expect_success 'get variable with empty value' ' echo novalue.variable > expect test_expect_success 'get-regexp variable with no value' ' - git config --get-regexp novalue > output && + git config ${mode_get_regexp} novalue > output && test_cmp expect output ' echo 'novalue.variable true' > expect test_expect_success 'get-regexp --bool variable with no value' ' - git config --bool --get-regexp novalue > output && + git config ${mode_get_regexp} --bool novalue > output && test_cmp expect output ' echo 'emptyvalue.variable ' > expect test_expect_success 'get-regexp variable with empty value' ' - git config --get-regexp emptyvalue > output && + git config ${mode_get_regexp} emptyvalue > output && test_cmp expect output ' @@ -1131,7 +1137,7 @@ test_expect_success 'quoting' ' ' test_expect_success 'key with newline' ' - test_must_fail git config "key.with + test_must_fail git config ${mode_get} "key.with newline" 123' test_expect_success 'value with newline' 'git config key.sub value.with\\\ @@ -1185,7 +1191,7 @@ test_expect_success '--null --list' ' ' test_expect_success '--null --get-regexp' ' - git config --null --get-regexp "val[0-9]" >result.raw && + git config ${mode_get_regexp} --null "val[0-9]" >result.raw && nul_to_q result && echo >>result && test_cmp expect result @@ -1194,21 +1200,21 @@ test_expect_success '--null --get-regexp' ' test_expect_success 'inner whitespace kept verbatim, spaces only' ' echo "foo bar" >expect && git config section.val "foo bar" && - git config --get section.val >actual && + git config ${mode_get} section.val >actual && test_cmp expect actual ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' ' echo "fooQQbar" | q_to_tab >expect && git config section.val "$(cat expect)" && - git config --get section.val >actual && + git config ${mode_get} section.val >actual && test_cmp expect actual ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' echo "foo Q bar" | q_to_tab >expect && git config section.val "$(cat expect)" && - git config --get section.val >actual && + git config ${mode_get} section.val >actual && test_cmp expect actual ' @@ -1283,11 +1289,11 @@ test_expect_success 'git -c can represent empty string' ' ' test_expect_success 'key sanity-checking' ' - test_must_fail git config foo=bar && - test_must_fail git config foo=.bar && - test_must_fail git config foo.ba=r && - test_must_fail git config foo.1bar && - test_must_fail git config foo."ba + test_must_fail git config ${mode_get} foo=bar && + test_must_fail git config ${mode_get} foo=.bar && + test_must_fail git config ${mode_get} foo.ba=r && + test_must_fail git config ${mode_get} foo.1bar && + test_must_fail git config ${mode_get} foo."ba z".bar && test_must_fail git config . false && test_must_fail git config .foo false && @@ -1336,7 +1342,7 @@ test_expect_success 'git -c complains about empty key and value' ' ' test_expect_success 'multiple git -c appends config' ' - test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" && + test_config alias.x "!git -c x.two=2 config ${mode_get_regexp} ^x\.*" && cat >expect <<-\EOF && x.one 1 x.two 2 @@ -1502,7 +1508,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' ' v="${SQ}key.one=foo${SQ}" && v="$v ${SQ}key.two=bar${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.one foo key.two bar @@ -1515,7 +1521,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' ' v="${SQ}key.one${SQ}=${SQ}foo${SQ}" && v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.one foo key.two bar @@ -1529,7 +1535,7 @@ test_expect_success 'old and new-style entries can mix' ' v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" && v="$v ${SQ}key.oldtwo=oldbar${SQ}" && v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.oldone oldfoo key.newone newfoo @@ -1542,7 +1548,7 @@ test_expect_success 'old and new-style entries can mix' ' test_expect_success 'old and new bools with ambiguous subsection' ' v="${SQ}key.with=equals.oldbool${SQ}" && v="$v ${SQ}key.with=equals.newbool${SQ}=" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.with equals.oldbool key.with=equals.newbool @@ -1556,7 +1562,7 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' ' env.two two EOF GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" >actual && + git config ${mode_get_regexp} "env.*" >actual && test_cmp expect actual && cat >expect <<-EOF && @@ -1564,12 +1570,12 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' ' env.two two EOF GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" >actual && + git config ${mode_get_regexp} "env.*" >actual && test_cmp expect actual && test_must_fail env \ GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" + git config ${mode_get_regexp} "env.*" ' test_expect_success 'git --config-env=key=envvar support' ' @@ -1617,7 +1623,7 @@ test_expect_success 'git -c and --config-env work together' ' ENVVAR=env-value git \ -c bar.cmd=cmd-value \ --config-env=bar.env=ENVVAR \ - config --get-regexp "^bar.*" >actual && + config ${mode_get_regexp} "^bar.*" >actual && test_cmp expect actual ' @@ -1645,7 +1651,7 @@ test_expect_success 'git config handles environment config pairs' ' GIT_CONFIG_COUNT=2 \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \ - git config --get-regexp "pair.*" >actual && + git config ${mode_get_regexp} "pair.*" >actual && cat >expect <<-EOF && pair.one foo pair.two bar @@ -1655,7 +1661,7 @@ test_expect_success 'git config handles environment config pairs' ' test_expect_success 'git config ignores pairs without count' ' test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' @@ -1663,7 +1669,7 @@ test_expect_success 'git config ignores pairs exceeding count' ' GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \ - git config --get-regexp "pair.*" >actual 2>error && + git config ${mode_get_regexp} "pair.*" >actual 2>error && cat >expect <<-EOF && pair.one value EOF @@ -1674,14 +1680,14 @@ test_expect_success 'git config ignores pairs exceeding count' ' test_expect_success 'git config ignores pairs with zero count' ' test_must_fail env \ GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' test_expect_success 'git config ignores pairs with empty count' ' test_must_fail env \ GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' @@ -1720,7 +1726,7 @@ test_expect_success 'environment overrides config file' ' one = value EOF GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \ - git config pair.one >actual && + git config ${mode_get} pair.one >actual && cat >expect <<-EOF && override EOF @@ -1730,7 +1736,7 @@ test_expect_success 'environment overrides config file' ' test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' ' GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \ GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \ - git config pair.one >actual && + git config ${mode_get} pair.one >actual && cat >expect <<-EOF && override EOF @@ -1805,20 +1811,28 @@ test_expect_success 'urlmatch' ' test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual && test_must_be_empty actual && + test_expect_code 1 git config get --url=https://good.example.com --bool doesnt.exist >actual && + test_must_be_empty actual && echo true >expect && git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual && test_cmp expect actual && + git config get --bool --url=https://good.example.com http.SSLverify >actual && + test_cmp expect actual && echo false >expect && git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual && test_cmp expect actual && + git config get --bool --url=https://weak.example.com http.sslverify >actual && + test_cmp expect actual && { echo http.cookiefile /tmp/cookie.txt && echo http.sslverify false } >expect && git config --get-urlmatch HTTP https://weak.example.com >actual && + test_cmp expect actual && + git config get --url=https://weak.example.com HTTP >actual && test_cmp expect actual ' @@ -1834,6 +1848,8 @@ test_expect_success 'urlmatch with --show-scope' ' local http.sslverify false EOF git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual && + test_cmp expect actual && + git config get --url=https://weak.example.com --show-scope HTTP >actual && test_cmp expect actual ' @@ -1866,45 +1882,67 @@ test_expect_success 'urlmatch favors more specific URLs' ' echo http.cookiefile /tmp/root.txt >expect && git config --get-urlmatch HTTP https://example.com >actual && test_cmp expect actual && + git config get --url=https://example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://example.com/subdirectory >actual && test_cmp expect actual && + git config get --url=https://example.com/subdirectory HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual && test_cmp expect actual && + git config get --url=https://example.com/subdirectory/nested HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/user.txt >expect && git config --get-urlmatch HTTP https://user@example.com/ >actual && test_cmp expect actual && + git config get --url=https://user@example.com/ HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual && test_cmp expect actual && + git config get --url=https://averylonguser@example.com/subdirectory HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/preceding.txt >expect && git config --get-urlmatch HTTP https://preceding.example.com >actual && test_cmp expect actual && + git config get --url=https://preceding.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/wildcard.txt >expect && git config --get-urlmatch HTTP https://wildcard.example.com >actual && test_cmp expect actual && + git config get --url=https://wildcard.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/sub.txt >expect && git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual && test_cmp expect actual && + git config get --url=https://sub.example.com/wildcardwithsubdomain HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/trailing.txt >expect && git config --get-urlmatch HTTP https://trailing.example.com >actual && test_cmp expect actual && + git config get --url=https://trailing.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/sub.txt >expect && git config --get-urlmatch HTTP https://user@sub.example.com >actual && test_cmp expect actual && + git config get --url=https://user@sub.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/multiwildcard.txt >expect && git config --get-urlmatch HTTP https://wildcard.example.org >actual && + test_cmp expect actual && + git config get --url=https://wildcard.example.org HTTP >actual && test_cmp expect actual ' @@ -2027,7 +2065,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [one] EOF git config --unset two.subsection.key && - test "not [two subsection]" = "$(git config one.key)" && + test "not [two subsection]" = "$(git config ${mode_get} one.key)" && test_line_count = 3 .git/config ' @@ -2150,7 +2188,7 @@ test_expect_success '--show-origin with --get-regexp' ' file:$HOME/.gitconfig user.global true file:.git/config user.local true EOF - git config --show-origin --get-regexp "user\.[g|l].*" >output && + git config ${mode_get_regexp} --show-origin "user\.[g|l].*" >output && test_cmp expect output ' @@ -2158,7 +2196,7 @@ test_expect_success '--show-origin getting a single key' ' cat >expect <<-\EOF && file:.git/config local EOF - git config --show-origin user.override >output && + git config ${mode_get} --show-origin user.override >output && test_cmp expect output ' @@ -2290,7 +2328,7 @@ test_expect_success '--show-scope getting a single value' ' cat >expect <<-\EOF && local true EOF - git config --show-scope --get user.local >output && + git config ${mode_get} --show-scope user.local >output && test_cmp expect output ' @@ -2559,9 +2597,9 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' # These modes complain when --fixed-value has no value-pattern test_must_fail git config --file=config --fixed-value dev.null bogus && test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus && - test_must_fail git config --file=config --fixed-value --get dev.null && - test_must_fail git config --file=config --fixed-value --get-all dev.null && - test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" && + test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null && + test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null && + test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" && test_must_fail git config --file=config --fixed-value --unset dev.null && test_must_fail git config --file=config --fixed-value --unset-all dev.null ' @@ -2591,12 +2629,12 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && test_must_fail git config --file=config --unset fixed.test "$META" && git config --file=config --fixed-value --unset fixed.test "$META" && - test_must_fail git config --file=config fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && cp initial config && test_must_fail git config --file=config --unset-all fixed.test "$META" && git config --file=config --fixed-value --unset-all fixed.test "$META" && - test_must_fail git config --file=config fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && cp initial config && git config --file=config --replace-all fixed.test bogus "$META" && @@ -2623,18 +2661,27 @@ test_expect_success '--get and --get-all with --fixed-value' ' git config --file=config --add fixed.test "$META" && git config --file=config --get fixed.test bogus && + git config get --file=config --value=bogus fixed.test && test_must_fail git config --file=config --get fixed.test "$META" && + test_must_fail git config get --file=config --value="$META" fixed.test && git config --file=config --get --fixed-value fixed.test "$META" && + git config get --file=config --fixed-value --value="$META" fixed.test && test_must_fail git config --file=config --get --fixed-value fixed.test non-existent && git config --file=config --get-all fixed.test bogus && + git config get --all --file=config --value=bogus fixed.test && test_must_fail git config --file=config --get-all fixed.test "$META" && + test_must_fail git config get --all --file=config --value="$META" fixed.test && git config --file=config --get-all --fixed-value fixed.test "$META" && + git config get --all --file=config --value="$META" --fixed-value fixed.test && test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent && git config --file=config --get-regexp fixed+ bogus && + git config get --regexp --file=config --value=bogus fixed+ && test_must_fail git config --file=config --get-regexp fixed+ "$META" && + test_must_fail git config get --regexp --file=config --value="$META" fixed+ && git config --file=config --get-regexp --fixed-value fixed+ "$META" && + git config get --regexp --file=config --fixed-value --value="$META" fixed+ && test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent ' From patchwork Mon May 6 08:56:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655179 Received: from wfout3-smtp.messagingengine.com (wfout3-smtp.messagingengine.com [64.147.123.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 188AF1422A4 for ; Mon, 6 May 2024 08:56:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985802; cv=none; b=lUMJm1lUxPq7Cif7txV4BbhfFwzZRgfpUj59rInVdoe4YMfSd9ENHZimjfIOvcTH2Hd3cErTBtjKWxTK3ky3MhfRgM4jdD/OMxnx4KiKdg5+QMscVNllLuThqokqVEMRUy5s4MkbzLwzsT3mW/XbEUNtLBxApgy425c0E8Lfh0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985802; c=relaxed/simple; bh=twR4AJIDHdfBrYcQQGnMQBJ/Uk/wjrKDMkNxNs6abWc=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=DbFZYx1Q5e/9jMwMnStjgE4HAoU212JDMxNzP66UnvxEz8Se0XkUJfqMSgzlchERP2ExySxAfC7rWFWFwnzC4TYpOhbL8pEwK2CWyFk7ceY31soZZ25w1dkA3rxPUxFW0suy0R0vtEGEK6TjqiT+xCpXXjIzY1y0/oMg6usZ1NM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=rhy1TIj6; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=IoxSTp6T; arc=none smtp.client-ip=64.147.123.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="rhy1TIj6"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="IoxSTp6T" Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailfout.west.internal (Postfix) with ESMTP id CC92A1C0013E; Mon, 6 May 2024 04:56:38 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Mon, 06 May 2024 04:56:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985798; x=1715072198; bh=U6hJ++rt1i XgWDbqIIVrjdhF2qOFddvoSq53PRVR+cs=; b=rhy1TIj6n/+5RNBmL8cELHGlAI 1v5fEmPS2aIh6nR/Ya4hoP9SzwfmvMGxEni5SNAidOWQL2peY9c4rhSFGe3/Jt6A V4rG7XvW2EQePLXEsktjhxsy0ZQmHt//lfzmFDcEVv2nfUruU6whYd6ETkUF90ZG Mr55vGMiTH9L+czi8c3Fp5tdgTRvFfg/y3hwVDNa+k9SwR/6bpl+sVCttU9t3s8j I/+Ryqv9HhTXiUHEKnUtxLOx5l50qZT/yHRxN0wNGrv/6tqo6j0q0aOB6H0v7B70 G1UawYzHN3SFYXwGkQXC/at06lkeSJXFgnEdCd0MXxZbcYmwYyQHY43P1vJw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985798; x=1715072198; bh=U6hJ++rt1iXgWDbqIIVrjdhF2qOF ddvoSq53PRVR+cs=; b=IoxSTp6TXBExzUHLgm2ox3QL//OOsUpHcQEeK4RmYNju XM0ShzwI7NgETdA8/SLjwMQEEEMV551Wgm01MMvRTWanuy2RKaZvgP4vvqLrStxF co1SbO5XQvKU1uKR4MGIc5uCGWIUyWK9HRa8iS3dU5uipHc4XR+ckjr0M5jY74lH +Kfl6aSIBrrbQis/0kMcDCk0jYElnMUsxe8ZxFN814CnswjIPxBwkvG9M0T09Xzq wC2IQx9t9Tt2m0mZnlLymXA8/SjyW22IbeCRgGs1mGaqJYA9x6Opo+naY9PKwPla lU8KhUVBGndqfN10Xx7lPSjCswoikxmvfSPxENpMJg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueejieetgfegleehjeelteejvedtteelteektdfguedvhedtvdefledvteejuedv necuffhomhgrihhnpehkvghrnhgvlhdrohhrghdpuhhnihhtrdhinhenucevlhhushhtvg hrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:36 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id ed4c2c31 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:30 +0000 (UTC) Date: Mon, 6 May 2024 10:56:33 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 09/14] builtin/config: introduce "set" subcommand Message-ID: <94afb5a5b7295de7ce7b22a0a4c612b431377eda.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "set" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 38 ++++++++----- builtin/config.c | 63 ++++++++++++++++++++++ t/t1300-config.sh | 102 ++++++++++++++++++----------------- 3 files changed, 140 insertions(+), 63 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index d0878663db..f57fa01085 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -11,9 +11,7 @@ SYNOPSIS [verse] 'git config list' [] [] [--includes] 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] -'git config' [] [--type=] [--comment=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] -'git config' [] [--type=] [--comment=] --add -'git config' [] [--type=] [--comment=] [--fixed-value] --replace-all [] +'git config set' [] [--type=] [--comment=] [--all] [--value=] [--fixed-value] 'git config' [] [--fixed-value] --unset [] 'git config' [] [--fixed-value] --unset-all [] 'git config' [] --rename-section @@ -27,7 +25,7 @@ You can query/set/replace/unset options with this command. The name is actually the section and the key separated by a dot, and the value will be escaped. -Multiple lines can be added to an option by using the `--add` option. +Multiple lines can be added to an option by using the `--append` option. If you want to update or unset an option which can occur on multiple lines, a `value-pattern` (which is an extended regular expression, unless the `--fixed-value` option is given) needs to be given. Only the @@ -82,6 +80,13 @@ get:: emits all values associated with key. Returns error code 1 if key is not present. +set:: + Set value for one or more config options. By default, this command + refuses to write multi-valued config options. Passing `--all` will + replace all multi-valued config options with the new value, whereas + `--value=` will replace all config options whose values match the given + pattern. + [[OPTIONS]] OPTIONS ------- @@ -90,10 +95,9 @@ OPTIONS Default behavior is to replace at most one line. This replaces all lines matching the key (and optionally the `value-pattern`). ---add:: +--append:: Adds a new line to the option without altering any existing - values. This is the same as providing '^$' as the `value-pattern` - in `--replace-all`. + values. This is the same as providing '--value=^$' in `set`. --comment :: Append a comment at the end of new or modified lines. @@ -296,6 +300,9 @@ recommended to migrate to the new syntax. 'git config ':: Replaced by `git config get `. +'git config []':: + Replaced by `git config set [--value=] `. + -l:: --list:: Replaced by `git config list`. @@ -315,6 +322,9 @@ recommended to migrate to the new syntax. --get-color []:: Replaced by `git config get --type=color [--default=] `. +--add :: + Replaced by `git config set --append `. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when @@ -361,7 +371,7 @@ precedence over values read earlier. When multiple values are taken then all values of a key from all files will be used. By default, options are only written to the repository specific -configuration file. Note that this also affects options like `--replace-all` +configuration file. Note that this also affects options like `set` and `--unset`. *'git config' will only ever change one file at a time*. You can limit which configuration sources are read from or written to by @@ -497,7 +507,7 @@ Given a .git/config like this: you can set the filemode to true with ------------ -% git config core.filemode true +% git config set core.filemode true ------------ The hypothetical proxy command entries actually have a postfix to discern @@ -505,7 +515,7 @@ what URL they apply to. Here is how to change the entry for kernel.org to "ssh". ------------ -% git config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$' +% git config set --value='for kernel.org$' core.gitproxy '"ssh" for kernel.org' ------------ This makes sure that only the key/value pair for kernel.org is replaced. @@ -541,26 +551,26 @@ If you like to live dangerously, you can replace *all* core.gitproxy by a new one with ------------ -% git config --replace-all core.gitproxy ssh +% git config set --all core.gitproxy ssh ------------ However, if you really only want to replace the line for the default proxy, i.e. the one without a "for ..." postfix, do something like this: ------------ -% git config core.gitproxy ssh '! for ' +% git config set --value='! for ' core.gitproxy ssh ------------ To actually match only values with an exclamation mark, you have to ------------ -% git config section.key value '[!]' +% git config set --value='[!]' section.key value ------------ To add a new proxy, without altering any of the existing ones, use ------------ -% git config --add core.gitproxy '"proxy-command" for example.com' +% git config set --append core.gitproxy '"proxy-command" for example.com' ------------ An example to use customized color from the configuration in your diff --git a/builtin/config.c b/builtin/config.c index 9e7ae49c02..87fd12fda2 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -18,6 +18,7 @@ static const char *const builtin_config_usage[] = { N_("git config list [] [] [--includes]"), N_("git config get [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] "), + N_("git config set [] [--type=] [--all] [--value=] [--fixed-value] "), NULL }; @@ -31,6 +32,11 @@ static const char *const builtin_config_get_usage[] = { NULL }; +static const char *const builtin_config_set_usage[] = { + N_("git config set [] [--type=] [--comment=] [--all] [--value=] [--fixed-value] "), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -849,9 +855,66 @@ static int cmd_config_get(int argc, const char **argv, const char *prefix) return get_value(argv[0], value_pattern, flags); } +static int cmd_config_set(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL, *comment_arg = NULL; + char *comment = NULL; + int flags = 0, append = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + 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), + OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_GROUP(N_("Other")), + OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")), + OPT_BOOL(0, "append", &append, N_("add a new line without altering any existing values")), + OPT_END(), + }; + struct key_value_info default_kvi = KVI_INIT; + char *value; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 2, 2); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with --value=")); + if (append && value_pattern) + die(_("--append cannot be used with --value=")); + if (append) + value_pattern = CONFIG_REGEX_NONE; + + comment = git_config_prepare_comment_string(comment_arg); + + handle_config_location(prefix); + + 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, + argv[0], value, value_pattern, + comment, flags); + } else { + ret = git_config_set_in_file_gently(given_config_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]); + } + + free(comment); + free(value); + return ret; +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), + OPT_SUBCOMMAND("set", &subcommand, cmd_config_set), OPT_END(), }; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 7ce13ed6cd..aa3f179be5 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -20,12 +20,16 @@ legacy) mode_get="" mode_get_all="--get-all" mode_get_regexp="--get-regexp" + mode_set="" + mode_replace_all="--replace-all" ;; subcommands) mode_prefix="" mode_get="get" mode_get_all="get --all" mode_get_regexp="get --regexp --all --show-names" + mode_set="set" + mode_replace_all="set --all" ;; *) BUG "unknown mode $mode";; @@ -132,7 +136,7 @@ cat > expect << EOF penguin = little blue EOF test_expect_success 'initial' ' - git config section.penguin "little blue" && + git config ${mode_set} section.penguin "little blue" && test_cmp expect .git/config ' @@ -142,7 +146,7 @@ cat > expect << EOF Movie = BadPhysics EOF test_expect_success 'mixed case' ' - git config Section.Movie BadPhysics && + git config ${mode_set} Section.Movie BadPhysics && test_cmp expect .git/config ' @@ -154,7 +158,7 @@ cat > expect << EOF WhatEver = Second EOF test_expect_success 'similar section' ' - git config Sections.WhatEver Second && + git config ${mode_set} Sections.WhatEver Second && test_cmp expect .git/config ' @@ -167,7 +171,7 @@ cat > expect << EOF WhatEver = Second EOF test_expect_success 'uppercase section' ' - git config SECTION.UPPERCASE true && + git config ${mode_set} SECTION.UPPERCASE true && test_cmp expect .git/config ' @@ -194,8 +198,8 @@ EOF test_expect_success 'append comments' ' git config --replace-all --comment="Pygoscelis papua" section.penguin gentoo && - git config --comment="find fish" section.disposition peckish && - git config --comment="#abc" section.foo bar && + git config ${mode_set} --comment="find fish" section.disposition peckish && + git config ${mode_set} --comment="#abc" section.foo bar && git config --comment="and comment" section.spsp value && git config --comment=" # and comment" section.htsp value && @@ -204,7 +208,7 @@ test_expect_success 'append comments' ' ' test_expect_success 'Prohibited LF in comment' ' - test_must_fail git config --comment="a${LF}b" section.k v + test_must_fail git config ${mode_set} --comment="a${LF}b" section.k v ' test_expect_success 'non-match result' 'test_cmp expect .git/config' @@ -301,14 +305,14 @@ test_expect_success 'multiple unset is correct' ' cp .git/config2 .git/config test_expect_success '--replace-all missing value' ' - test_must_fail git config --replace-all beta.haha && + test_must_fail git config ${mode_replace_all} beta.haha && test_cmp .git/config2 .git/config ' rm .git/config2 test_expect_success '--replace-all' ' - git config --replace-all beta.haha gamma + git config ${mode_replace_all} beta.haha gamma ' cat > expect << EOF @@ -335,7 +339,7 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF test_expect_success 'really mean test' ' - git config beta.haha alpha && + git config ${mode_set} beta.haha alpha && test_cmp expect .git/config ' @@ -350,7 +354,7 @@ noIndent= sillyValue ; 'nother silly comment nonewline = wow EOF test_expect_success 'really really mean test' ' - git config nextsection.nonewline wow && + git config ${mode_set} nextsection.nonewline wow && test_cmp expect .git/config ' @@ -824,16 +828,16 @@ EOF test_expect_success 'section ending' ' rm -f .git/config && - git config gitcvs.enabled true && - git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && - git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && + git config ${mode_set} gitcvs.enabled true && + git config ${mode_set} gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && + git config ${mode_set} gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && test_cmp expect .git/config ' test_expect_success numbers ' - git config kilo.gram 1k && - git config mega.ton 1m && + git config ${mode_set} kilo.gram 1k && + git config ${mode_set} mega.ton 1m && echo 1024 >expect && echo 1048576 >>expect && git config --int --get kilo.gram >actual && @@ -842,20 +846,20 @@ test_expect_success numbers ' ' test_expect_success '--int is at least 64 bits' ' - git config giga.watts 121g && + git config ${mode_set} giga.watts 121g && echo >expect && test_cmp_config 129922760704 --int --get giga.watts ' test_expect_success 'invalid unit' ' - git config aninvalid.unit "1auto" && + git config ${mode_set} aninvalid.unit "1auto" && test_cmp_config 1auto aninvalid.unit && test_must_fail git config --int --get aninvalid.unit 2>actual && test_grep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual ' test_expect_success 'invalid unit boolean' ' - git config commit.gpgsign "1true" && + git config ${mode_set} commit.gpgsign "1true" && test_cmp_config 1true commit.gpgsign && test_must_fail git config --bool --get commit.gpgsign 2>actual && test_grep "bad boolean config value .1true. for .commit.gpgsign." actual @@ -885,14 +889,14 @@ EOF test_expect_success bool ' - git config bool.true1 01 && - git config bool.true2 -1 && - git config bool.true3 YeS && - git config bool.true4 true && - git config bool.false1 000 && - git config bool.false2 "" && - git config bool.false3 nO && - git config bool.false4 FALSE && + git config ${mode_set} bool.true1 01 && + git config ${mode_set} bool.true2 -1 && + git config ${mode_set} bool.true3 YeS && + git config ${mode_set} bool.true4 true && + git config ${mode_set} bool.false1 000 && + git config ${mode_set} bool.false2 "" && + git config ${mode_set} bool.false3 nO && + git config ${mode_set} bool.false4 FALSE && rm -f result && for i in 1 2 3 4 do @@ -903,7 +907,7 @@ test_expect_success bool ' test_expect_success 'invalid bool (--get)' ' - git config bool.nobool foobar && + git config ${mode_set} bool.nobool foobar && test_must_fail git config --bool --get bool.nobool' test_expect_success 'invalid bool (set)' ' @@ -1092,7 +1096,7 @@ test_expect_success 'get --expiry-date' ' test_expect_success 'get --type=color' ' rm .git/config && - git config foo.color "red" && + git config ${mode_set} foo.color "red" && git config --get --type=color foo.color >actual.raw && test_decode_color actual && echo "" >expect && @@ -1129,10 +1133,10 @@ cat > expect << EOF EOF test_expect_success 'quoting' ' rm -f .git/config && - git config quote.leading " test" && - git config quote.ending "test " && - git config quote.semicolon "test;test" && - git config quote.hash "test#test" && + git config ${mode_set} quote.leading " test" && + git config ${mode_set} quote.ending "test " && + git config ${mode_set} quote.semicolon "test;test" && + git config ${mode_set} quote.hash "test#test" && test_cmp expect .git/config ' @@ -1140,7 +1144,7 @@ test_expect_success 'key with newline' ' test_must_fail git config ${mode_get} "key.with newline" 123' -test_expect_success 'value with newline' 'git config key.sub value.with\\\ +test_expect_success 'value with newline' 'git config ${mode_set} key.sub value.with\\\ newline' cat > .git/config <<\EOF @@ -1199,21 +1203,21 @@ test_expect_success '--null --get-regexp' ' test_expect_success 'inner whitespace kept verbatim, spaces only' ' echo "foo bar" >expect && - git config section.val "foo bar" && + git config ${mode_set} section.val "foo bar" && git config ${mode_get} section.val >actual && test_cmp expect actual ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' ' echo "fooQQbar" | q_to_tab >expect && - git config section.val "$(cat expect)" && + git config ${mode_set} section.val "$(cat expect)" && git config ${mode_get} section.val >actual && test_cmp expect actual ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' echo "foo Q bar" | q_to_tab >expect && - git config section.val "$(cat expect)" && + git config ${mode_set} section.val "$(cat expect)" && git config ${mode_get} section.val >actual && test_cmp expect actual ' @@ -1252,12 +1256,12 @@ test_expect_success 'check split_cmdline return' ' git init repo && ( cd repo && - git config alias.split-cmdline-fix "echo \"" && + git config ${mode_set} alias.split-cmdline-fix "echo \"" && test_must_fail git split-cmdline-fix && echo foo >foo && git add foo && git commit -m "initial commit" && - git config branch.main.mergeoptions "echo \"" && + git config ${mode_set} branch.main.mergeoptions "echo \"" && test_must_fail git merge main ) ' @@ -1295,12 +1299,12 @@ test_expect_success 'key sanity-checking' ' test_must_fail git config ${mode_get} foo.1bar && test_must_fail git config ${mode_get} foo."ba z".bar && - test_must_fail git config . false && - test_must_fail git config .foo false && - test_must_fail git config foo. false && - test_must_fail git config .foo. false && - git config foo.bar true && - git config foo."ba =z".bar false + test_must_fail git config ${mode_set} . false && + test_must_fail git config ${mode_set} .foo false && + test_must_fail git config ${mode_set} foo. false && + test_must_fail git config ${mode_set} .foo. false && + git config ${mode_set} foo.bar true && + git config ${mode_set} foo."ba =z".bar false ' test_expect_success 'git -c works with aliases of builtins' ' @@ -2523,7 +2527,7 @@ test_expect_success '--replace-all does not invent newlines' ' [abc] Qkey = b EOF - git config --replace-all abc.key b && + git config ${mode_replace_all} abc.key b && test_cmp expect .git/config ' @@ -2595,8 +2599,8 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config --file=config --fixed-value --get-colorbool dev.null && # These modes complain when --fixed-value has no value-pattern - test_must_fail git config --file=config --fixed-value dev.null bogus && - test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus && + test_must_fail git config ${mode_set} --file=config --fixed-value dev.null bogus && + test_must_fail git config ${mode_replace_all} --file=config --fixed-value dev.null bogus && test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null && test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null && test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" && @@ -2637,7 +2641,7 @@ test_expect_success '--fixed-value uses exact string matching' ' test_must_fail git config ${mode_get} --file=config fixed.test && cp initial config && - git config --file=config --replace-all fixed.test bogus "$META" && + git config --file=config fixed.test bogus "$META" && git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=$META From patchwork Mon May 6 08:56:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655180 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA4371422D8 for ; Mon, 6 May 2024 08:56:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985805; cv=none; b=XgwU0OBUmQrJuGuWyRc4gZY1R9h7RIOtPlVLdSEyl8yULu16b5d2lkhDBHMwWuxGIvaMSD2hWph2gLmbZOUjUFEDqhVkk3MLhH3+yfeh2PyIW1YBLlXyFoQpgvqnJEC0nZczRu5F/M8B/qiYXYudDAORAud7BYGrfhGkrlkfA2A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985805; c=relaxed/simple; bh=Q8ZMj9icnrUpe+Up6TiX1iVSNFm8ApCLPyiVKGFOeaI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=BoX9pLHqWG6i6y8C8brtlxgNGBsTA3g+lbGWtO2lNIQdSE/vh9NaQq5OQ4/WwJJEhILAWmhPcNg2wvYkxGCwolnMd8O1vrHTmq2KyfxGJia9HvOAcH+U5BE0f30Erz/5ZGpSIPowKXXDOCXOIMq3wjd2Wl0OB9FBirzYZlBBbNM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=sUkPOkWz; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=R0cvdUge; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="sUkPOkWz"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="R0cvdUge" Received: from compute7.internal (compute7.nyi.internal [10.202.2.48]) by mailfhigh.west.internal (Postfix) with ESMTP id BD0BF18000CC; Mon, 6 May 2024 04:56:42 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Mon, 06 May 2024 04:56:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985802; x=1715072202; bh=HviME28Q4e NMiZRwL9jLRK0pV0Tkhhp4SGBXvlbzxx0=; b=sUkPOkWz/u5/rQ/dBD1PrWxzEH SrBZ4Ni6uN2Ztm04PsgIP6isHOt+fpIkv+Wyjf+QssOGHTrIDaUW0nOsEfqle/7w XjHb8k9yvb4chQhX4QTbSq2Bk/LAZ949lP8NW3SeDSStEDylIDGbwDfSm3NTiG2Q E7/8g6XHYQ1H7QbYe/5Xr5gB1QH9vZSTw/L7YpKmvOha27ETVVt5QPdI1mZwaJtw dO4KRzyDg4MAQcQVPAU/UX5N9Zxu6SdP5fKj85yUoJcyRe6G1SQWe8oo+qmqFQYy t+bEMmFHvXFGoPEloDSbYWs7dOpj5hPb0pCzs3QKWDt1lSL0eu8hQlVlaNcQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985802; x=1715072202; bh=HviME28Q4eNMiZRwL9jLRK0pV0Tk hhp4SGBXvlbzxx0=; b=R0cvdUgeAOU3+RUt9k2GOBfm2rqu27uYNC4APQ/TnvLV meO/Ea5zyiHqC6Vcr9lKqfJTJeH4mOSwf4frYFoF0nHlHc+DM59B2aWQRCc+9iu/ Ew9PFFtQslXSzJHnA3hctijl4aAvmRe5RwJtgrRzyIrTir1NiuxUxQeuMtpJWzsO VE2c/eyLjBcTmDw83UOIVtEY26/TEBKcU6YLnYt9WAXrzk7hrN7MCqEusJcvneKz 1xN+Z5L7QwIT+9fTOzT+E3hBKkUxM9+XQ2xXKReypbkeRKgZhrwKAlU5Ygwfi5kl aADT2LtvJXy7NZ5Ol6uS8CM9CmnNaGUgnQgWyBPDxQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepieevkedtgffgleeugfdvledvfedthfegueegfeevjeelueefkeegfeffhefglefg necuffhomhgrihhnpehkvghrnhgvlhdrohhrghenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:40 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 086a5cb7 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:35 +0000 (UTC) Date: Mon, 6 May 2024 10:56:38 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 10/14] builtin/config: introduce "unset" subcommand Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "unset" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 27 +++++++++++++--------- builtin/config.c | 39 ++++++++++++++++++++++++++++++++ t/t1300-config.sh | 44 ++++++++++++++++++++++++------------ 3 files changed, 84 insertions(+), 26 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index f57fa01085..5575fe55ea 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -11,9 +11,8 @@ SYNOPSIS [verse] 'git config list' [] [] [--includes] 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] -'git config set' [] [--type=] [--comment=] [--all] [--value=] [--fixed-value] -'git config' [] [--fixed-value] --unset [] -'git config' [] [--fixed-value] --unset-all [] +'git config set' [] [--type=] [--all] [--value=] [--fixed-value] +'git config unset' [] [--all] [--value=] [--fixed-value] 'git config' [] --rename-section 'git config' [] --remove-section 'git config' [] --get-colorbool [] @@ -87,6 +86,12 @@ set:: `--value=` will replace all config options whose values match the given pattern. +unset:: + Unset value for one or more config options. By default, this command + refuses to unset multi-valued keys. Passing `--all` will unset all + multi-valued config options, whereas `--value` will unset all config + options whose values match the given pattern. + [[OPTIONS]] OPTIONS ------- @@ -190,12 +195,6 @@ See also <>. --rename-section:: Rename the given section to a new name. ---unset:: - Remove the line matching the key from config file. - ---unset-all:: - Remove all lines matching the key from config file. - --fixed-value:: When used with the `value-pattern` argument, treat `value-pattern` as an exact string instead of a regular expression. This will restrict @@ -325,6 +324,12 @@ recommended to migrate to the new syntax. --add :: Replaced by `git config set --append `. +--unset []:: + Replaced by `git config unset [--value=] `. + +--unset-all []:: + Replaced by `git config unset [--value=] --all `. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when @@ -372,7 +377,7 @@ values of a key from all files will be used. By default, options are only written to the repository specific configuration file. Note that this also affects options like `set` -and `--unset`. *'git config' will only ever change one file at a time*. +and `unset`. *'git config' will only ever change one file at a time*. You can limit which configuration sources are read from or written to by specifying the path of a file with the `--file` option, or by specifying a @@ -523,7 +528,7 @@ This makes sure that only the key/value pair for kernel.org is replaced. To delete the entry for renames, do ------------ -% git config --unset diff.renames +% git config unset diff.renames ------------ If you want to delete an entry for a multivar (like core.gitproxy above), diff --git a/builtin/config.c b/builtin/config.c index 87fd12fda2..2578d4c930 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -19,6 +19,7 @@ static const char *const builtin_config_usage[] = { N_("git config list [] [] [--includes]"), N_("git config get [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] "), N_("git config set [] [--type=] [--all] [--value=] [--fixed-value] "), + N_("git config unset [] [--all] [--value=] [--fixed-value] "), NULL }; @@ -37,6 +38,11 @@ static const char *const builtin_config_set_usage[] = { NULL }; +static const char *const builtin_config_unset_usage[] = { + N_("git config unset [] [--all] [--value=] [--fixed-value] "), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -911,10 +917,43 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix) return ret; } +static int cmd_config_unset(int argc, const char **argv, const char *prefix) +{ + const char *value_pattern = NULL; + int flags = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + 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")), + OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_unset_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 1, 1); + + if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern) + die(_("--fixed-value only applies with 'value-pattern'")); + + handle_config_location(prefix); + + if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], NULL, value_pattern, + NULL, flags); + else + return git_config_set_in_file_gently(given_config_source.file, argv[0], + NULL, NULL); +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), OPT_SUBCOMMAND("set", &subcommand, cmd_config_set), + OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset), OPT_END(), }; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index aa3f179be5..2ab58bbd95 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -22,6 +22,8 @@ legacy) mode_get_regexp="--get-regexp" mode_set="" mode_replace_all="--replace-all" + mode_unset="--unset" + mode_unset_all="--unset-all" ;; subcommands) mode_prefix="" @@ -30,6 +32,8 @@ subcommands) mode_get_regexp="get --regexp --all --show-names" mode_set="set" mode_replace_all="set --all" + mode_unset="unset" + mode_unset_all="unset --all" ;; *) BUG "unknown mode $mode";; @@ -259,7 +263,7 @@ foo = bar EOF test_expect_success 'unset with cont. lines' ' - git config --unset beta.baz + git config ${mode_unset} beta.baz ' cat > expect <<\EOF @@ -286,7 +290,7 @@ EOF cp .git/config .git/config2 test_expect_success 'multiple unset' ' - git config --unset-all beta.haha + git config ${mode_unset_all} beta.haha ' cat > expect << EOF @@ -372,7 +376,7 @@ noIndent= sillyValue ; 'nother silly comment nonewline = wow EOF test_expect_success 'unset' ' - git config --unset beta.haha && + git config ${mode_unset} beta.haha && test_cmp expect .git/config ' @@ -428,11 +432,11 @@ test_expect_success 'multivar replace' ' ' test_expect_success 'ambiguous unset' ' - test_must_fail git config --unset nextsection.nonewline + test_must_fail git config ${mode_unset} nextsection.nonewline ' test_expect_success 'invalid unset' ' - test_must_fail git config --unset somesection.nonewline + test_must_fail git config ${mode_unset} somesection.nonewline ' cat > expect << EOF @@ -446,7 +450,12 @@ noIndent= sillyValue ; 'nother silly comment EOF test_expect_success 'multivar unset' ' - git config --unset nextsection.nonewline "wow3$" && + case "$mode" in + legacy) + git config --unset nextsection.nonewline "wow3$";; + subcommands) + git config unset --value="wow3$" nextsection.nonewline;; + esac && test_cmp expect .git/config ' @@ -2013,7 +2022,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' # please be careful when you update the above variable EOF - git config --unset section.key && + git config ${mode_unset} section.key && test_cmp expect .git/config && cat >.git/config <<-\EOF && @@ -2026,7 +2035,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [next-section] EOF - git config --unset section.key && + git config ${mode_unset} section.key && test_cmp expect .git/config && q_to_tab >.git/config <<-\EOF && @@ -2036,7 +2045,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [two] key = true EOF - git config --unset two.key && + git config ${mode_unset} two.key && ! grep two .git/config && q_to_tab >.git/config <<-\EOF && @@ -2046,7 +2055,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [one] key = true EOF - git config --unset-all one.key && + git config ${mode_unset_all} one.key && test_line_count = 0 .git/config && q_to_tab >.git/config <<-\EOF && @@ -2056,7 +2065,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [two] Qkey = true EOF - git config --unset two.key && + git config ${mode_unset} two.key && grep two .git/config && q_to_tab >.git/config <<-\EOF && @@ -2068,7 +2077,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [TWO "subsection"] [one] EOF - git config --unset two.subsection.key && + git config ${mode_unset} two.subsection.key && test "not [two subsection]" = "$(git config ${mode_get} one.key)" && test_line_count = 3 .git/config ' @@ -2080,7 +2089,7 @@ test_expect_success '--unset-all removes section if empty & uncommented' ' key = value2 EOF - git config --unset-all section.key && + git config ${mode_unset_all} section.key && test_line_count = 0 .git/config ' @@ -2604,8 +2613,8 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null && test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null && test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" && - test_must_fail git config --file=config --fixed-value --unset dev.null && - test_must_fail git config --file=config --fixed-value --unset-all dev.null + test_must_fail git config ${mode_unset} --file=config --fixed-value dev.null && + test_must_fail git config ${mode_unset_all} --file=config --fixed-value dev.null ' test_expect_success '--fixed-value uses exact string matching' ' @@ -2635,6 +2644,11 @@ test_expect_success '--fixed-value uses exact string matching' ' git config --file=config --fixed-value --unset fixed.test "$META" && test_must_fail git config ${mode_get} --file=config fixed.test && + cp initial config && + test_must_fail git config unset --file=config --value="$META" fixed.test && + git config unset --file=config --fixed-value --value="$META" fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && + cp initial config && test_must_fail git config --file=config --unset-all fixed.test "$META" && git config --file=config --fixed-value --unset-all fixed.test "$META" && From patchwork Mon May 6 08:56:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655181 Received: from wfout3-smtp.messagingengine.com (wfout3-smtp.messagingengine.com [64.147.123.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E05F31422D0 for ; Mon, 6 May 2024 08:56:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985810; cv=none; b=PAQ2CCCS7X9jafyOQJ+c7D1ARYByKCT+oKbvN6z0iGww6OHaOmW01GuJS2RgqVWyWF/rhXvs+5/UaEEYinKjBMKjqSL6JkNDzFbNNdZFkAqMdHXH0XBswBhtY6QuVTkM+4r3xpscFciEZ+EHyZkwNJL7vhSn2F4Qa6JfXRMkQMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985810; c=relaxed/simple; bh=ItUyQnbSaQXzVVwB0QWlVMaMOoPo/TVpx0OH9ZVs0vA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=TISx+vcWql7Yp6QweGXJ2C9eInK3jQQh0sTA4Fl2kz1eajCIEGCXiQGhR/VJckZJaRyIh/CNfXLoPE7SkTr/7DnDXbRVA3tu571I1T8IKGdb1WMo/HvYK8NhhQB2t4mIwzlhXrUktrS6zd1ye1gMIiqb65Q84qT6ggeep0gjv6g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=GRHaNxAC; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Ohkrs6/2; arc=none smtp.client-ip=64.147.123.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="GRHaNxAC"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ohkrs6/2" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfout.west.internal (Postfix) with ESMTP id B119A1C0012E; Mon, 6 May 2024 04:56:47 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 06 May 2024 04:56:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985807; x=1715072207; bh=F/bYwzmBiw +JzFjGCwWmcfiSFEvlOWvCHgPbVwUhNb4=; b=GRHaNxACjw+HSq7ElI1n3p4uHX 2l7PB6YFMkfYNFAJWt1KXzF4/z6eulAX2Mhb1EpE3Bxflv6uCr9EAvrabPy9WuOj bck39in4s1PfICUyZTYxb5zIaYUtEYxIzA8GTD8d/BKqTa75DRlqg4hjhBniV3YC Gb1mPbv0UT9Sl8+k8Qdp3aNVhzd4NTbYg3HkZwvQa5YquwZBpQICzEvNE7HU/0EM kcaaVfgNZgFXc9kifYU7jW8bjfeEVNwHfKXERz3kHO6iuGspGzsHTEojjYvI3eKb nDpfUGSYrfgdjUn5bWT3RQ48GSyhy9LK+3Sw3wpbvTL80k0cdbUzNsTtAvcg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985807; x=1715072207; bh=F/bYwzmBiw+JzFjGCwWmcfiSFEvl OWvCHgPbVwUhNb4=; b=Ohkrs6/2cvkKlOZFKvaT/oEn+xlMaco1p098woh7Q/l+ ajmcrett9Apy8JCHYaf4Nxw0hRq9l0DxXPC0jeMbbShxcOsy8y38n1KYtrWi30Nk eJmgsuN1zTz9uMKv1D/fUkjzeKuKVCRFGFj+1vOk4JbXdfIXtD9zT0srd2rET4kk z2rgH3Aoce6Odl4OPHafpAH1zks+1+PLPX3W6YR+/ENiT2j919oboEEAkYfh5OFd /9dGPDsbIR0g3/JYXmfSwKYSN76o2HscKhWCXE1oag8xN2JgjLXDe9XSHuVAFQkv P8zffUyrhcmZYh968Mifsuw0np98MJmQG1+9VRt4/A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepfeenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:45 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id fda5ce5d (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:40 +0000 (UTC) Date: Mon, 6 May 2024 10:56:43 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 11/14] builtin/config: introduce "rename-section" subcommand Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "rename-section" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 11 +++++++---- builtin/config.c | 32 ++++++++++++++++++++++++++++++++ t/t1300-config.sh | 22 +++++++++++----------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 5575fe55ea..ede86ad085 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -13,7 +13,7 @@ SYNOPSIS 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] 'git config set' [] [--type=] [--all] [--value=] [--fixed-value] 'git config unset' [] [--all] [--value=] [--fixed-value] -'git config' [] --rename-section +'git config rename-section' [] 'git config' [] --remove-section 'git config' [] --get-colorbool [] 'git config' [] -e | --edit @@ -92,6 +92,9 @@ unset:: multi-valued config options, whereas `--value` will unset all config options whose values match the given pattern. +rename-section:: + Rename the given section to a new name. + [[OPTIONS]] OPTIONS ------- @@ -192,9 +195,6 @@ See also <>. --remove-section:: Remove the given section from the configuration file. ---rename-section:: - Rename the given section to a new name. - --fixed-value:: When used with the `value-pattern` argument, treat `value-pattern` as an exact string instead of a regular expression. This will restrict @@ -330,6 +330,9 @@ recommended to migrate to the new syntax. --unset-all []:: Replaced by `git config unset [--value=] --all `. +--rename-section :: + Replaced by `git config rename-section `. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when diff --git a/builtin/config.c b/builtin/config.c index 2578d4c930..a60dca9b2b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -20,6 +20,7 @@ static const char *const builtin_config_usage[] = { N_("git config get [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] "), N_("git config set [] [--type=] [--all] [--value=] [--fixed-value] "), N_("git config unset [] [--all] [--value=] [--fixed-value] "), + N_("git config rename-section [] "), NULL }; @@ -43,6 +44,11 @@ static const char *const builtin_config_unset_usage[] = { NULL }; +static const char *const builtin_config_rename_section_usage[] = { + N_("git config rename-section [] "), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -949,11 +955,37 @@ static int cmd_config_unset(int argc, const char **argv, const char *prefix) NULL, NULL); } +static int cmd_config_rename_section(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_rename_section_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 2, 2); + + handle_config_location(prefix); + + ret = git_config_rename_section_in_file(given_config_source.file, + argv[0], argv[1]); + if (ret < 0) + return ret; + else if (!ret) + die(_("no such section: %s"), argv[0]); + + return 0; +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), OPT_SUBCOMMAND("set", &subcommand, cmd_config_set), OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset), + OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section), OPT_END(), }; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 2ab58bbd95..5d7b08fa4c 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -699,7 +699,7 @@ weird EOF test_expect_success 'rename section' ' - git config --rename-section branch.eins branch.zwei + git config ${mode_prefix}rename-section branch.eins branch.zwei ' cat > expect << EOF @@ -718,7 +718,7 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'rename non-existing section' ' - test_must_fail git config --rename-section \ + test_must_fail git config ${mode_prefix}rename-section \ branch."world domination" branch.drei ' @@ -727,7 +727,7 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'rename another section' ' - git config --rename-section branch."1 234 blabl/a" branch.drei + git config ${mode_prefix}rename-section branch."1 234 blabl/a" branch.drei ' cat > expect << EOF @@ -750,7 +750,7 @@ cat >> .git/config << EOF EOF test_expect_success 'rename a section with a var on the same line' ' - git config --rename-section branch.vier branch.zwei + git config ${mode_prefix}rename-section branch.vier branch.zwei ' cat > expect << EOF @@ -771,11 +771,11 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'renaming empty section name is rejected' ' - test_must_fail git config --rename-section branch.zwei "" + test_must_fail git config ${mode_prefix}rename-section branch.zwei "" ' test_expect_success 'renaming to bogus section is rejected' ' - test_must_fail git config --rename-section branch.zwei "bogus name" + test_must_fail git config ${mode_prefix}rename-section branch.zwei "bogus name" ' test_expect_success 'renaming a section with a long line' ' @@ -784,7 +784,7 @@ test_expect_success 'renaming a section with a long line' ' printf " c = d %1024s [a] e = f\\n" " " && printf "[a] g = h\\n" } >y && - git config -f y --rename-section a xyz && + git config ${mode_prefix}rename-section -f y a xyz && test_must_fail git config -f y b.e ' @@ -794,7 +794,7 @@ test_expect_success 'renaming an embedded section with a long line' ' printf " c = d %1024s [a] [foo] e = f\\n" " " && printf "[a] g = h\\n" } >y && - git config -f y --rename-section a xyz && + git config ${mode_prefix}rename-section -f y a xyz && test_must_fail git config -f y foo.e ' @@ -804,7 +804,7 @@ test_expect_success 'renaming a section with an overly-long line' ' printf " c = d %525000s e" " " && printf "[a] g = h\\n" } >y && - test_must_fail git config -f y --rename-section a xyz 2>err && + test_must_fail git config ${mode_prefix}rename-section -f y a xyz 2>err && grep "refusing to work with overly long line in .y. on line 2" err ' @@ -2112,7 +2112,7 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' ' git config imap.pass Hunter2 && perl -e \ "die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" && - git config --rename-section imap pop && + git config ${mode_prefix}rename-section imap pop && perl -e \ "die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600" ' @@ -2601,7 +2601,7 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config --file=config --fixed-value --add dev.null bogus && test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && - test_must_fail git config --file=config --fixed-value --rename-section dev null && + test_must_fail git config ${mode_prefix}rename-section --file=config --fixed-value dev null && test_must_fail git config --file=config --fixed-value --remove-section dev && test_must_fail git config ${mode_prefix}list --file=config --fixed-value && test_must_fail git config --file=config --fixed-value --get-color dev.null && From patchwork Mon May 6 08:56:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655182 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D29911422A7 for ; Mon, 6 May 2024 08:56:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985815; cv=none; b=qcRXsCFmHCFyjNmcAP0rnreaE10ZTanCfX9gCCt3GyXi2gTK6ti6JJR8B96TO2VvnjRRN+QPnwx/aN19sP5ab27mFdsTpnJW1IIWV09++wqp1F1jBiPdNvq3dGYRx5e6HQdqckpgDCgCFrZ54nBNAg+KkYswV0cTcE5BF0qkIes= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985815; c=relaxed/simple; bh=49yspa44GMZx2HRE2gtjDewdFxbhL26qvyPLAbzysD4=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=MK/PQIVwGUhZTtewuQu/hYPbPJ1PtpQu4FB0x6Dst/njWdQXTTSg7WdOnfbqe2h96KeuHqdG5lDKdxuf6329e6nL0OLXdZNUR2Rb48DKB+WXlQns8uq86Ys3sk2CfzXF6lWQwA2NpMsSqScd7aOdCynGqOwgfl18eiZsAM01+yw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=TauaP8H9; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=gfY4ZHeZ; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="TauaP8H9"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gfY4ZHeZ" Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.west.internal (Postfix) with ESMTP id A2ADA18000D2; Mon, 6 May 2024 04:56:52 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Mon, 06 May 2024 04:56:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985812; x=1715072212; bh=g5p3VpYQCJ JbYWmg2oNPK9uWkgJin0kMiNZ2SsnFtFE=; b=TauaP8H969+lG6QZXtGK2aEkHW pilTLuHHONKwbd8GRT3dckJUcNLTvrxYRWl77vHKwk9z9XmTlR/QG4hh98b9mxNV YiszFAIM5F9RnAhZ1UhWS5N6LuGgh/sBz+H+Ti4LTl+7SlMiPQWaSTT56Pia4KjP o10jawv/M2yn6y6eRpw/dr8srKIKtjiOgPRv8T+7yelKslmxDVeonshlSuvmWkpP 60wh9BygZgpDEtgOfyQpK7ik89M8DSD0nF3GZ4KLqiyf1iuGRfFKY7hZe86DeU5E 9vzfzwGudE0NZpaJtHCrkss6IZWXyzaow/QZ+a4hmaUEmskTIDrfIng/C6Tg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985812; x=1715072212; bh=g5p3VpYQCJJbYWmg2oNPK9uWkgJi n0kMiNZ2SsnFtFE=; b=gfY4ZHeZHwA+cyTY8qIx+YDPnXE1DTEFusibEGk+oU+z RvjfJSHqCzkjG2UoH2bgXxOveud6dFsYeN7MpMmCw0iOIolaokWmb/QIHQfpn2SF zIChw7lgFA95eiTc1fXdFmH2RoR7a3hBZ30JZ+dEZqyue0Ji6Udqqpw4CZNSfeqT lTGTMfUi2Kbwy5vx/X9mCXHi7nCCZutc9QjW2/PPqFOW0n2FYl5FBAO8pkPqCTV7 5jNkJKDDy4Y1WVppA13nxrDlCSn6vcoPXAry9azOaVK4dOJp1lmIbOcVjBT7CUoj TlY+OuQSdffxa/8XDyzfFYyYFQHbfqfXl7da88xsfw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedgtdelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:50 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 39c9cb1c (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:44 +0000 (UTC) Date: Mon, 6 May 2024 10:56:47 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 12/14] builtin/config: introduce "remove-section" subcommand Message-ID: <8ec214755ea1e37f2b49e9d5f88a8d719ed84996.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "remove-section" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 11 +++++++---- builtin/config.c | 32 ++++++++++++++++++++++++++++++++ t/t1300-config.sh | 4 ++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index ede86ad085..ef46520c15 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -14,7 +14,7 @@ SYNOPSIS 'git config set' [] [--type=] [--all] [--value=] [--fixed-value] 'git config unset' [] [--all] [--value=] [--fixed-value] 'git config rename-section' [] -'git config' [] --remove-section +'git config remove-section' [] 'git config' [] --get-colorbool [] 'git config' [] -e | --edit @@ -95,6 +95,9 @@ unset:: rename-section:: Rename the given section to a new name. +remove-section:: + Remove the given section from the configuration file. + [[OPTIONS]] OPTIONS ------- @@ -192,9 +195,6 @@ See also <>. section in linkgit:gitrevisions[7] for a more complete list of ways to spell blob names. ---remove-section:: - Remove the given section from the configuration file. - --fixed-value:: When used with the `value-pattern` argument, treat `value-pattern` as an exact string instead of a regular expression. This will restrict @@ -333,6 +333,9 @@ recommended to migrate to the new syntax. --rename-section :: Replaced by `git config rename-section `. +--remove-section :: + Replaced by `git config remove-section `. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when diff --git a/builtin/config.c b/builtin/config.c index a60dca9b2b..cea03fb517 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -21,6 +21,7 @@ static const char *const builtin_config_usage[] = { N_("git config set [] [--type=] [--all] [--value=] [--fixed-value] "), N_("git config unset [] [--all] [--value=] [--fixed-value] "), N_("git config rename-section [] "), + N_("git config remove-section [] "), NULL }; @@ -49,6 +50,11 @@ static const char *const builtin_config_rename_section_usage[] = { NULL }; +static const char *const builtin_config_remove_section_usage[] = { + N_("git config remove-section [] "), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -980,12 +986,38 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr return 0; } +static int cmd_config_remove_section(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + int ret; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_remove_section_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + check_write(); + check_argc(argc, 1, 1); + + handle_config_location(prefix); + + ret = git_config_rename_section_in_file(given_config_source.file, + argv[0], NULL); + if (ret < 0) + return ret; + else if (!ret) + die(_("no such section: %s"), argv[0]); + + return 0; +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), OPT_SUBCOMMAND("set", &subcommand, cmd_config_set), OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset), OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section), + OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section), OPT_END(), }; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 5d7b08fa4c..9d71ec1260 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -813,7 +813,7 @@ cat >> .git/config << EOF EOF test_expect_success 'remove section' ' - git config --remove-section branch.zwei + git config ${mode_prefix}remove-section branch.zwei ' cat > expect << EOF @@ -2602,7 +2602,7 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && test_must_fail git config ${mode_prefix}rename-section --file=config --fixed-value dev null && - test_must_fail git config --file=config --fixed-value --remove-section dev && + test_must_fail git config ${mode_prefix}remove-section --file=config --fixed-value dev && test_must_fail git config ${mode_prefix}list --file=config --fixed-value && test_must_fail git config --file=config --fixed-value --get-color dev.null && test_must_fail git config --file=config --fixed-value --get-colorbool dev.null && From patchwork Mon May 6 08:56:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655183 Received: from wfout3-smtp.messagingengine.com (wfout3-smtp.messagingengine.com [64.147.123.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A30E41422A7 for ; Mon, 6 May 2024 08:56:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985820; cv=none; b=oCW6zAIEYz7oaeOGu7lHVEsGqwHqUj0iYrPcOeWpbpGjYiatHTPeHOkNt6RWdycfTJQqi7+NR6dY0At4jLFNVLctn9U7vlZIDCFgLVuapvuqPHJv0dgF1tZrfwj+4WjJvSHv7JlNL52KdmaCI4FhgV3OTSLFgyLssW3B9e6x+bY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985820; c=relaxed/simple; bh=O6S9J94zeCk05aeNBKP3r0L01W0EWtZYt3fBwxiB4zk=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=lmN1CI/v27Pyerh/2c0ZHCyJIygIXBy0f4bF9V2cInFF/fN0Tf6GjaF9fGkkNi/ROjlvSC3IHn1iWmJJgnPvm+popy1LLF2pPtu3V89RsDMeKCYkYWYy7QdciInID37bU3/2wOp9Mb750moLgmZBZsEcbgwSIP+NeDFVGVoDqY8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=Rhi4ksnf; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=b55OmuCy; arc=none smtp.client-ip=64.147.123.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="Rhi4ksnf"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="b55OmuCy" Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailfout.west.internal (Postfix) with ESMTP id 927181C0012E; Mon, 6 May 2024 04:56:57 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Mon, 06 May 2024 04:56:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985817; x=1715072217; bh=b7iJmiMKCl Coxu6dfljLANIrxXolpcvQRNPRmVVXYZA=; b=Rhi4ksnf12NPRnlk0tS80P6ZZ1 LBQJLQ7yuC7QoDUXnMA99T1iiwEj+3cWfaLvciH1Oh9ANtrx94N9sl8f1CYys62O OWXi62TU3c13eTNPxtHNJxbWiDBG5L7+78bCI+RPQWLzY5l9lJyN6lfYY57xbRvi KZyED3PEdq68ihKlwnqVZwKr89usxlH1AmHWUiZt8gTpRVBAphnAwb3/vbP5m7ah 7MrdcGJI6YEHkZkUrkY9opULCDTS1SuGsbbBWn8di9o68kZXq1t42taayDjpUris 2YLyEP93VAl1CWseDfDVpsjxqqFuO9eVM6D89D1M0s+cRJ/i47Es6ODq2H/g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985817; x=1715072217; bh=b7iJmiMKClCoxu6dfljLANIrxXol pcvQRNPRmVVXYZA=; b=b55OmuCyhpxtHSEK03/uv9z/yLkz5A47q6d/jF24/2hh RHuoIXTECWOEFd4VPQW5EiLSA503eZT8ynsaaZSsdi6YTfFavubm6rg48urwnsHF bQ5toNVYENnVti/kW3xItKpGukeEgzgYdz+3Z+ZHQtgECjhvWkWBb5P4wssCOPTO PWeA21m+U9cEASuET/zSdPu2hKHzmH595YSaL5fAGSylEzMFb6IvpBROuvDZ3TCW fsDpRWdVZO966veX6EsFwTXcfpVWy7fd5kTja58U0qQXJSls8QAWaCFk2Z6Z2g41 Dp3BFfiPEr+Mb4ypALOUz8MaddIBMr1DJ7i20LVjbg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:55 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id d5c094d3 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:49 +0000 (UTC) Date: Mon, 6 May 2024 10:56:52 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 13/14] builtin/config: introduce "edit" subcommand Message-ID: <1893c23afc982e1d442f50b5e4b8ab0073aaa05d.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce a new "edit" subcommand to git-config(1). Please refer to preceding commits regarding the motivation behind this change. Signed-off-by: Patrick Steinhardt --- Documentation/git-config.txt | 17 ++++---- builtin/config.c | 81 ++++++++++++++++++++++++------------ t/t1300-config.sh | 6 +-- 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index ef46520c15..65c645d461 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -15,8 +15,8 @@ SYNOPSIS 'git config unset' [] [--all] [--value=] [--fixed-value] 'git config rename-section' [] 'git config remove-section' [] +'git config edit' [] 'git config' [] --get-colorbool [] -'git config' [] -e | --edit DESCRIPTION ----------- @@ -98,6 +98,11 @@ rename-section:: remove-section:: Remove the given section from the configuration file. +edit:: + Opens an editor to modify the specified config file; either + `--system`, `--global`, `--local` (default), `--worktree`, or + `--file `. + [[OPTIONS]] OPTIONS ------- @@ -274,12 +279,6 @@ Valid ``'s include: When the color setting for `name` is undefined, the command uses `color.ui` as fallback. --e:: ---edit:: - Opens an editor to modify the specified config file; either - `--system`, `--global`, `--local` (default), `--worktree`, or - `--file `. - --[no-]includes:: Respect `include.*` directives in config files when looking up values. Defaults to `off` when a specific file is given (e.g., @@ -336,6 +335,10 @@ recommended to migrate to the new syntax. --remove-section :: Replaced by `git config remove-section `. +-e:: +--edit:: + Replaced by `git config edit`. + CONFIGURATION ------------- `pager.config` is only respected when listing configuration, i.e., when diff --git a/builtin/config.c b/builtin/config.c index cea03fb517..8f7fa8f31a 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -22,6 +22,7 @@ static const char *const builtin_config_usage[] = { N_("git config unset [] [--all] [--value=] [--fixed-value] "), N_("git config rename-section [] "), N_("git config remove-section [] "), + N_("git config edit []"), NULL }; @@ -55,6 +56,11 @@ static const char *const builtin_config_remove_section_usage[] = { NULL }; +static const char *const builtin_config_edit_usage[] = { + N_("git config edit []"), + NULL +}; + static char *key; static regex_t *key_regexp; static const char *value_pattern; @@ -1011,6 +1017,53 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr return 0; } +static int show_editor(void) +{ + char *config_file; + + if (!given_config_source.file && !startup_info->have_repository) + die(_("not in a git directory")); + if (given_config_source.use_stdin) + die(_("editing stdin is not supported")); + if (given_config_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) : + git_pathdup("config"); + if (use_global_config) { + int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd >= 0) { + char *content = default_user_config(); + write_str_in_full(fd, content); + free(content); + close(fd); + } + else if (errno != EEXIST) + die_errno(_("cannot create configuration file %s"), config_file); + } + launch_editor(config_file, NULL, NULL); + free(config_file); + + return 0; +} + +static int cmd_config_edit(int argc, const char **argv, const char *prefix) +{ + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0); + check_write(); + check_argc(argc, 0, 0); + + handle_config_location(prefix); + + return show_editor(); +} + static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("get", &subcommand, cmd_config_get), @@ -1018,6 +1071,7 @@ static struct option builtin_subcommand_options[] = { OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset), OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section), OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section), + OPT_SUBCOMMAND("edit", &subcommand, cmd_config_edit), OPT_END(), }; @@ -1144,32 +1198,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (actions == ACTION_EDIT) { - char *config_file; - - check_argc(argc, 0, 0); - if (!given_config_source.file && !startup_info->have_repository) - die(_("not in a git directory")); - if (given_config_source.use_stdin) - die(_("editing stdin is not supported")); - if (given_config_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) : - git_pathdup("config"); - if (use_global_config) { - int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (fd >= 0) { - char *content = default_user_config(); - write_str_in_full(fd, content); - free(content); - close(fd); - } - else if (errno != EEXIST) - die_errno(_("cannot create configuration file %s"), config_file); - } - launch_editor(config_file, NULL, NULL); - free(config_file); + ret = show_editor(); } else if (actions == ACTION_SET) { check_write(); diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 9d71ec1260..f3c4d28e06 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -666,7 +666,7 @@ test_expect_success 'setting a value in stdin is an error' ' ' test_expect_success 'editing stdin is an error' ' - test_must_fail git config --file - --edit + test_must_fail git config ${mode_prefix}edit --file - ' test_expect_success 'refer config from subdirectory' ' @@ -1768,7 +1768,7 @@ test_expect_success 'command line overrides environment config' ' test_expect_success 'git config --edit works' ' git config -f tmp test.value no && echo test.value=yes >expect && - GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit && + GIT_EDITOR="echo [test]value=yes >" git config ${mode_prefix}edit -f tmp && git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' @@ -1777,7 +1777,7 @@ test_expect_success 'git config --edit respects core.editor' ' git config -f tmp test.value no && echo test.value=yes >expect && test_config core.editor "echo [test]value=yes >" && - git config -f tmp --edit && + git config ${mode_prefix}edit -f tmp && git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' From patchwork Mon May 6 08:56:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13655184 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A6CCA1422A7 for ; Mon, 6 May 2024 08:57:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985824; cv=none; b=JpewAGUDg0EtDOvxBfP67JIlrweTqLPiW7Vr9VrysiAeH4YKAnJOjbtWhTkAY0PwL/hj2N37YVG+380e9Y9J2GjM6FMa/3qqayVClCGZ+zDaK+usoy90+BUQfhjCKoeZrYqA6vPTjodS1AYpkMtL7GxMiN/3GpDRsC8OT0QGuys= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714985824; c=relaxed/simple; bh=8YV1WOX1PwIJoDkHtFa7J3R2eb5BToXiqs4c0K2Tqfg=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=fHRfVtUBE9KnBPNXOYA4+pszTbEKAT1XTvfN1yXa7k7N0oWgtyViH9AtRwk2MJT7LO2RjEdQUnqtmrdYkABcyzm0xZyhwEJPjUggntE9LvwrToOa53OBxOy7HZsisNC0O3EnpeTpEVh9Iz5FesnZbnaeg9DViDYJJVO3tjBBxuw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=aS9X5U9l; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=WcEAUpMv; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="aS9X5U9l"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="WcEAUpMv" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfhigh.west.internal (Postfix) with ESMTP id 7A07618000C6; Mon, 6 May 2024 04:57:01 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 06 May 2024 04:57:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1714985821; x=1715072221; bh=/5d+HXocPQ RZnKc3WRy9DN7Viy5bRByg6Vdy87Ax0QA=; b=aS9X5U9lz2RfKyUCmF/TbCoGth ue98KZvRgiDW1TidBgBiDKw2aEjqbZcVNmNLWX7S16t959GUuLsGu1D6C7/2DyOM axTVQgqdgJyM5W51jiJJ7CXwHQxPyv34YYrl3SjCHCJV/tOW2TdWIjMS2Iy07wbr vU6R8ZwJ60uBR61XKQeESSAnhP/ZiaitEzgxllwUTHoPLyX13SqfXSP9fCJ0tVvu q/3cFsdOVozD+itThiUAoBpkfXwVnbzCKvgXdQYQ2Z2NarJbRO7bFiQlo6u0+6sL Ql7sRU53ZjCWlXU0DSkSErd00jBIjKjzRU23N4Gp9+JbbiYS4J76BAVUY57Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1714985821; x=1715072221; bh=/5d+HXocPQRZnKc3WRy9DN7Viy5b RByg6Vdy87Ax0QA=; b=WcEAUpMvEz63PW7d/jLUy7J8RvjjAaipagOAn+x5LFMp tcyhVukGMiKljRTOSACy6CTkGTsTZCBGib2qaqzxqUTpIjRf9eA69E3F2RTLeOWV rsLIAsfMmo0nphcXM2WX8se6qw52amIt/BrSNdY1Lxsi8/WtZvjqad0O4D8UuyMA vwaoosz1of0yLhyZJKPyTcCZNcewMGbiY/zTAmMjPoulPTiP1sakmagGcZSVmI6Y JkdyP0oOEWXNj7VGLE84q5K1Aa+tCMHj0f4HJUI3BdH5uWveo5cUrr2IN3dQh0HY JBlJJzFkAj17Bs9z/pMxuxiZxd85lKTbXVS7FidW6g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddviedguddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepgeenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 6 May 2024 04:56:59 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 66896b9c (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 6 May 2024 08:56:54 +0000 (UTC) Date: Mon, 6 May 2024 10:56:57 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Taylor Blau , =?iso-8859-1?q?Jean-No=EBl?= AVILA , Eric Sunshine , Junio C Hamano , Dragan Simic , rsbecker@nexbridge.com Subject: [PATCH v5 14/14] builtin/config: display subcommand help Message-ID: <97a48ab81dba0ab03cc3c1b648555a5fab79ee0a.1714982328.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Until now, `git config -h` would have printed help for the old-style syntax. Now that all modes have proper subcommands though it is preferable to instead display the subcommand help. Drop the `NO_INTERNAL_HELP` flag to do so. While at it, drop the help mismatch in t0450 and add the `--get-colorbool` option to the usage such that git-config(1)'s synopsis and `git config -h` match. Signed-off-by: Patrick Steinhardt --- builtin/config.c | 5 +++-- t/t0450/txt-help-mismatches | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 8f7fa8f31a..80aa9d8a66 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -23,6 +23,7 @@ static const char *const builtin_config_usage[] = { N_("git config rename-section [] "), N_("git config remove-section [] "), N_("git config edit []"), + N_("git config [] --get-colorbool []"), NULL }; @@ -1093,10 +1094,10 @@ int cmd_config(int argc, const char **argv, const char *prefix) * us when parsing the legacy-style modes that don't use subcommands. */ argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, - PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_NO_INTERNAL_HELP|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT); + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT); if (subcommand) { argc = parse_options(argc, argv, prefix, builtin_subcommand_options, builtin_config_usage, - PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_NO_INTERNAL_HELP|PARSE_OPT_KEEP_UNKNOWN_OPT); + PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT); return subcommand(argc, argv, prefix); } diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches index a0777acd66..28003f18c9 100644 --- a/t/t0450/txt-help-mismatches +++ b/t/t0450/txt-help-mismatches @@ -10,7 +10,6 @@ checkout checkout-index clone column -config credential credential-cache credential-store