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" && -- 2.44.GIT