From patchwork Wed Mar 27 08:46: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: 13605957 Received: from fout7-smtp.messagingengine.com (fout7-smtp.messagingengine.com [103.168.172.150]) (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 3C0071E869 for ; Wed, 27 Mar 2024 08:46:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.150 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711529213; cv=none; b=lEUGY406NsztZYC8hAqLfOvgpyGkO0Vv9cE32kNNUA0ekWT6djv4VSLY3I1N7Lo+DfxDsgnvmC2ldrrzgAo18XzPlUb/M8HZgrX9oadBWuF/e/XIAQG0pj84v7GI2P1s14XRWz9/MXuy1LcjU7gfhZJjUTMWNeAu2bLUrKujJ6o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711529213; c=relaxed/simple; bh=s8F6yFuoIxBrmUcu3PYJNR/fLqP9IuqXKG/m2SOAJVE=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=VjMTA5u08XFzUjIg6GddkLmqgkPm2U4cK9uklZfEHpjSHWZIzbJhcWN7Dr21vm4pQfxZCc2+DAsKRE8dQ52fHyrIfPPnLuXk2Am9PIHoJPaa2TcEMjRnjkVbKqC9oMOqf0IDLQZgQTC/6ld+u6mnIPntq28t5ceOL5oUlC51MP0= 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=gLdcc3Ps; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=TsMyuwR2; arc=none smtp.client-ip=103.168.172.150 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="gLdcc3Ps"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="TsMyuwR2" Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailfout.nyi.internal (Postfix) with ESMTP id 5759B138015E; Wed, 27 Mar 2024 04:46:50 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 27 Mar 2024 04:46:50 -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=fm2; t=1711529210; x=1711615610; bh=9tq7zqU4dr EYmiQokqR9Sm3A7sqwiigTEcYDUbLbeGg=; b=gLdcc3PsNc0yFKxS42N9YOMjqI FZV1QPIbP48LkzSS/tKrrUNNG1OU3zcEBSUqd8FHDqKKWlCVY+R3EB2Qr/IIKwyj BYIXM6mUDsv2dL5+1mhjMiZPJRQWTn53UbS1cuFp+5WRC3KGiLO3COStQ0+nV8J4 53BDkHovse5CrBRqukr3jmmNMWfSXkAuMpLr1IP8rzVi5rkZUrPPXczvyQEDxV6b sK2FIqwwttZKz8cM0vC5IRzIPXUHa5EYwjjy+U+n3kbIdi7RAc/ZnQEm9Rpq8K9O bv5XoMr4Q54/NTQiFuvaoaetzHebO2FANuxix+98sQaZQlcNtA4VuTVNj5vA== 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= fm2; t=1711529210; x=1711615610; bh=9tq7zqU4drEYmiQokqR9Sm3A7sqw iigTEcYDUbLbeGg=; b=TsMyuwR2q/9NlXf5dsBNpS9zSIgTAKHBdbr+8pJ6PE2k izcJ1k7xN4eUBRQfwUmWcS87OQbcDxvCrX5rguLRuXFNY1dt6/ao0S2DDefunWel FWrE6tpBLEuvwW0HWmgSjvLpRNpIM+/Pzc4qUhyK9/OmdDI6TdhXEiCK+LDqmFag llb/dPQtk+xlvSua2KLrBS7vEoRO3DuTQP8IgruAPVIRaqTHcU2jueDsMX7aG7Uy KoCA0bq4VY4E3SMSLZSdzuNwR+ltIwX9s/FMJ7UsaS52+7MNRih0ZCINweUop0mI G8ZmKrxQUAXgJ6F1thoOO+8rZ8tesWvT91gQhnr+eA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledruddugedguddvgecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpeffhffvvefukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrght rhhitghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucggtffrrghtth gvrhhnpeeiveektdfggfeluefgvdelvdeftdfhgeeugeefveejleeufeekgeefffehgfel gfenucffohhmrghinhepkhgvrhhnvghlrdhorhhgnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 27 Mar 2024 04:46:48 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 9c381e8f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 27 Mar 2024 08:46:35 +0000 (UTC) Date: Wed, 27 Mar 2024 09:46:47 +0100 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 Subject: [PATCH v3 09/13] builtin/config: introduce "unset" subcommand Message-ID: <90f055ae1d9e735560b66dc9aac534fafaf27c23.1711527812.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 "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 | 25 ++++++++++++-------- builtin/config.c | 38 +++++++++++++++++++++++++++++++ t/t1300-config.sh | 44 ++++++++++++++++++++++++------------ 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 7fdf9b434e..4fbc73a19e 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -12,8 +12,7 @@ SYNOPSIS 'git config list' [] [] [--includes] 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] 'git config set' [] [--type=] [--all] [--value=] [--fixed-value] -'git config' [] [--fixed-value] --unset [] -'git config' [] [--fixed-value] --unset-all [] +'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 ------- @@ -178,12 +183,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 @@ -313,6 +312,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 @@ -360,7 +365,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 @@ -511,7 +516,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 eec57fbd17..c53b68887e 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; @@ -903,10 +909,42 @@ 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, + flags); + else + return git_config_set_in_file_gently(given_config_source.file, argv[0], 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 f435b8f194..c9610a1f5b 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";; @@ -149,7 +153,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 @@ -176,7 +180,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 @@ -262,7 +266,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 ' @@ -318,11 +322,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 @@ -336,7 +340,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 ' @@ -1887,7 +1896,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 && @@ -1900,7 +1909,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 && @@ -1910,7 +1919,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 && @@ -1920,7 +1929,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 && @@ -1930,7 +1939,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 && @@ -1942,7 +1951,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 ' @@ -1954,7 +1963,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 ' @@ -2478,8 +2487,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' ' @@ -2509,6 +2518,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" &&