From patchwork Fri May 3 09:56:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13652596 Received: from wfhigh8-smtp.messagingengine.com (wfhigh8-smtp.messagingengine.com [64.147.123.159]) (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 933EF14F9D5 for ; Fri, 3 May 2024 09:56:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.159 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714730211; cv=none; b=j3lU8Wq8Z52e3KA8q+uUjsyKO8m64mYyoAb8JNOVaSXfLmsyYCweEfRjF1Sq9O78mm2IPa+RbuZ9nfwcvdPAol72XwMjeQxwVBIG7gpKcJayqTkyI3Z6n8aaOeDrtRJQIzulefuv+27nILqwxdLvFRIeFCdzU3LunXl3Cr1YVJ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714730211; c=relaxed/simple; bh=uFVmGiJ6woewGW0lIJHPzHwZHrctFoGqu+13ycw6lng=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=swyPwJvEyqMgBk6M5n+yjbV5DfQBb844wER+xxsosBavYdH5v3M4qcGUP70syk3SlnhNi/2zZRH7Em6wD5eiusujCzhwu0BY95RwOc0Oy5xfHgAeWoyBd5Vj0DBV+SJJ2DM42KV2se+d4GbNPjc/Deu/51HYXQ+w43BJuE5XGOw= 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=vD/zHgO0; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=gKsedMUt; arc=none smtp.client-ip=64.147.123.159 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="vD/zHgO0"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gKsedMUt" Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailfhigh.west.internal (Postfix) with ESMTP id 7601718000BA; Fri, 3 May 2024 05:56:47 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Fri, 03 May 2024 05:56:47 -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=1714730207; x=1714816607; bh=a8JAXxRRpA K6GIkqUZfDaAFO+GeJoRMqWAuyLvcX4oc=; b=vD/zHgO0XCjr2pMNygtUPJgNoX kCxBhN9MRNCYOs+1Ks/f/FMqbvaHtBHYjdHU/075U51qd1arK8g1E0FIdJJ7vIXe nQyrrPT6XPn7Rxl4J1Z9o+h0a1OkZ/X3S1Ud/LARPy1dwZX28GKxjkxYC1eBiv4t v0R+w/ztPl36kJjzyYgxahVhYnGQ2rZjKxvSm6hASb/XmXFoORtM6ZpZBb4dUaw1 UEZ9BzCk++Bby4PlBD63Tax7TKPpVK+QpsrqlRu+xgY4qSFUb7/L7YDdqsULyCyH LWNR8DkOhMwirVmltjjV7tVwTo8uI48QCnJMXQl5Df9yQsIqCMxJ84092wsw== 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=1714730207; x=1714816607; bh=a8JAXxRRpAK6GIkqUZfDaAFO+GeJ oRMqWAuyLvcX4oc=; b=gKsedMUt/TkvVNZvXpGwahLOEtdZzWU65A9aTt1PaVum rGNhGmupFidN5E/mpDFLMTJ9wUlL/Grpautjs/tDcLhVPlCkO69nZ5/BkwT9NKB7 zA+M9SJsyApA+M/Z/D0cvHHozsSOY3+gAkid+uvoopg65kSQ0YGxDpIh9V9HGun+ W58cLG9lSvpOOs4Hh4e1jIGaqRC/43ejhLTUN4CVKV+/8UHS1uIqmPED7560QB8u 034FcM1RousDuIjFQkEoPv0ABjMrC2BDsOb79z/ZGjdZsoadn5D/JzeVlrqoXRsW CYZ1IiGgMG+50KMNbvGd6ulRU5LWnKpFNOBnNgrI+Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvddvtddgvddtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 3 May 2024 05:56:45 -0400 (EDT) Received: by localhost (OpenSMTPD) with ESMTPSA id 24fcbc08 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Fri, 3 May 2024 09:56:14 +0000 (UTC) Date: Fri, 3 May 2024 11:56:40 +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 Subject: [PATCH v4 00/14] builtin/config: introduce subcommands 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: Hi, this is the fourth version of my patch series that introduces subcommands for git-config(1). Changes compared to v3: - Rebased on top of d4cc1ec35f (Start the 2.46 cycle, 2024-04-30). - Implemented support for `git config set --comment`. This switch has been added since the last version of this patch series. Here's hoping that there's a bit more interest in this patch series at the beginning of the release cycle :) Patrick Patrick Steinhardt (14): config: clarify memory ownership when preparing comment strings builtin/config: move option array around builtin/config: move "fixed-value" option to correct group builtin/config: use `OPT_CMDMODE()` to specify modes builtin/config: pull out function to handle config location builtin/config: pull out function to handle `--null` builtin/config: introduce "list" subcommand builtin/config: introduce "get" subcommand builtin/config: introduce "set" subcommand builtin/config: introduce "unset" subcommand builtin/config: introduce "rename-section" subcommand builtin/config: introduce "remove-section" subcommand builtin/config: introduce "edit" subcommand builtin/config: display subcommand help Documentation/git-config.txt | 219 ++++++++------- builtin/config.c | 512 ++++++++++++++++++++++++++++------- config.c | 16 +- config.h | 2 +- t/t0450/txt-help-mismatches | 1 - t/t1300-config.sh | 432 +++++++++++++++++------------ 6 files changed, 812 insertions(+), 370 deletions(-) Range-diff against v3: -: ---------- > 1: 3aa26d5bff config: clarify memory ownership when preparing comment strings 1: bfcb50e393 ! 2: 8f0804ab48 builtin/config: move option array around @@ builtin/config.c: static int option_parse_type(const struct option *opt, const c - 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(), -}; - @@ builtin/config.c: static char *default_user_config(void) + 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(), +}; + 2: ff428d8a22 ! 3: ddcd8031d7 builtin/config: move "fixed-value" option to correct group @@ builtin/config.c: static struct option builtin_config_options[] = { 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), @@ builtin/config.c: 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_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(), }; 3: e049c05713 = 4: 1bc3918840 builtin/config: use `OPT_CMDMODE()` to specify modes 4: 41585803bf ! 5: 3754812309 builtin/config: pull out function to handle config location @@ builtin/config.c: static char *default_user_config(void) - 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) -+static void handle_config_location(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; @@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix + 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(), +}; @@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix + +int cmd_config(int argc, const char **argv, const char *prefix) +{ -+ char *value = NULL; ++ char *value = NULL, *comment = NULL; + int flags = 0; + int ret = 0; + struct key_value_info default_kvi = KVI_INIT; 5: 95f661f267 = 6: cb1714c493 builtin/config: pull out function to handle `--null` 6: b50f32d074 ! 7: b3f3c3ba6a builtin/config: introduce "list" subcommand @@ Documentation/git-config.txt: git-config - Get and set repository or global opti -------- [verse] +'git config list' [] [] [--includes] - 'git config' [] [--type=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] - 'git config' [] [--type=] --add - 'git config' [] [--type=] [--fixed-value] --replace-all [] + '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 [] @@ Documentation/git-config.txt: SYNOPSIS 'git config' [] [--fixed-value] --unset-all [] 'git config' [] --rename-section @@ builtin/config.c: 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_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(), @@ builtin/config.c: static NORETURN void usage_builtin_config(void) + int cmd_config(int argc, const char **argv, const char *prefix) { - char *value = NULL; + char *value = NULL, *comment = NULL; @@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix) given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); @@ t/t1300-config.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + BUG "unknown mode $mode";; +esac + - test_expect_success 'clear default config' ' - rm -f .git/config - ' + test_expect_success 'setup whitespace config' ' + sed -e "s/^|//" \ + -e "s/[$]$//" \ @@ t/t1300-config.sh: version.1.2.3eX.alpha=beta EOF @@ t/t1300-config.sh: Qsection.sub=section.val4 nul_to_q result && echo >>result && test_cmp expect result -@@ t/t1300-config.sh: test_expect_success 'inner whitespace kept verbatim' ' +@@ t/t1300-config.sh: test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' test_expect_success SYMLINKS 'symlinked configuration' ' 7: eee1fae50c ! 8: 0e6da909ac builtin/config: introduce "get" subcommand @@ Documentation/git-config.txt: SYNOPSIS [verse] 'git config list' [] [] [--includes] +'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] - 'git config' [] [--type=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] - 'git config' [] [--type=] --add - 'git config' [] [--type=] [--fixed-value] --replace-all [] + '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 [] @@ Documentation/git-config.txt: COMMANDS OPTIONS ------- @@ Documentation/git-config.txt: OPTIONS - values. This is the same as providing '^$' as the `value-pattern` - in `--replace-all`. + not contain linefeed characters (no multi-line comments are + permitted). ---get:: - Get the value for a given key (optionally filtered by a regex @@ Documentation/git-config.txt: OPTIONS ---get-all:: - Like get, but returns all values for a multi-valued key. +--all:: -+ With `get`, Return all values for a multi-valued key. ++ With `get`, return all values for a multi-valued key. ---get-regexp:: - Like --get-all, but interprets the name as a regular expression and @@ t/t1300-config.sh: test_expect_success '--null --list' ' nul_to_q result && echo >>result && test_cmp expect result +@@ t/t1300-config.sh: 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 + ' + @@ t/t1300-config.sh: test_expect_success 'git -c can represent empty string' ' ' 8: e2815affab ! 9: 8a623a31b9 builtin/config: introduce "set" subcommand @@ Documentation/git-config.txt: SYNOPSIS [verse] 'git config list' [] [] [--includes] 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] --'git config' [] [--type=] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] [ []] --'git config' [] [--type=] --add --'git config' [] [--type=] [--fixed-value] --replace-all [] -+'git config set' [] [--type=] [--all] [--value=] [--fixed-value] +-'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 @@ Documentation/git-config.txt: OPTIONS - in `--replace-all`. + values. This is the same as providing '--value=^$' in `set`. - --all:: - With `get`, Return all values for a multi-valued key. + --comment :: + Append a comment at the end of new or modified lines. @@ Documentation/git-config.txt: recommended to migrate to the new syntax. 'git config ':: Replaced by `git config get `. @@ builtin/config.c: static const char *const builtin_config_get_usage[] = { }; +static const char *const builtin_config_set_usage[] = { -+ N_("git config set [] [--type=] [--all] [--value=] [--fixed-value] "), ++ N_("git config set [] [--type=] [--comment=] [--all] [--value=] [--fixed-value] "), + NULL +}; + @@ builtin/config.c: static int cmd_config_get(int argc, const char **argv, const c +static int cmd_config_set(int argc, const char **argv, const char *prefix) +{ -+ const char *value_pattern = NULL; ++ const char *value_pattern = NULL, *comment_arg = NULL; ++ char *comment = NULL; + int flags = 0, append = 0; + struct option opts[] = { + CONFIG_LOCATION_OPTIONS, @@ builtin/config.c: static int cmd_config_get(int argc, const char **argv, const c + 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(), + }; @@ builtin/config.c: static int cmd_config_get(int argc, const char **argv, const c + 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); @@ builtin/config.c: static int cmd_config_get(int argc, const char **argv, const c + 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, -+ flags); ++ comment, flags); + } else { -+ ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value); ++ 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; +} @@ t/t1300-config.sh: cat > expect << EOF test_cmp expect .git/config ' +@@ t/t1300-config.sh: 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 && +@@ t/t1300-config.sh: 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' @@ t/t1300-config.sh: test_expect_success 'multiple unset is correct' ' cp .git/config2 .git/config @@ t/t1300-config.sh: test_expect_success 'key with newline' ' cat > .git/config <<\EOF @@ t/t1300-config.sh: 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' ' -- git config section.val "foo bar" && -+ git config ${mode_set} section.val "foo bar" && - test_cmp_config "foo bar" section.val + 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 + ' @@ t/t1300-config.sh: test_expect_success 'check split_cmdline return' ' git init repo && ( 9: 90f055ae1d ! 10: e25e5b69cd builtin/config: introduce "unset" subcommand @@ Commit message ## Documentation/git-config.txt ## @@ Documentation/git-config.txt: SYNOPSIS + [verse] 'git config list' [] [] [--includes] 'git config get' [] [] [--includes] [--all] [--regexp=] [--value=] [--fixed-value] [--default=] - 'git config set' [] [--type=] [--all] [--value=] [--fixed-value] +-'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 @@ builtin/config.c: static int cmd_config_set(int argc, const char **argv, const c + 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); ++ NULL, flags); + else -+ return git_config_set_in_file_gently(given_config_source.file, argv[0], NULL); ++ return git_config_set_in_file_gently(given_config_source.file, argv[0], ++ NULL, NULL); +} + static struct option builtin_subcommand_options[] = { 10: 3e360b1f47 ! 11: f24008d356 builtin/config: introduce "rename-section" subcommand @@ builtin/config.c: static const char *const builtin_config_unset_usage[] = { static regex_t *key_regexp; static const char *value_pattern; @@ builtin/config.c: static int cmd_config_unset(int argc, const char **argv, const char *prefix) - return git_config_set_in_file_gently(given_config_source.file, argv[0], NULL); + NULL, NULL); } +static int cmd_config_rename_section(int argc, const char **argv, const char *prefix) 11: d610b5fda1 = 12: fc2ddd3201 builtin/config: introduce "remove-section" subcommand 12: 4a6512c88a = 13: 4c2d817eff builtin/config: introduce "edit" subcommand 13: 657d1355b5 = 14: 4c351b12b8 builtin/config: display subcommand help