]> git.ipfire.org Git - thirdparty/git.git/commitdiff
parseopt: values of pathname type can be prefixed with :(optional)
authorJunio C Hamano <gitster@pobox.com>
Sun, 28 Sep 2025 21:29:16 +0000 (17:29 -0400)
committerJunio C Hamano <gitster@pobox.com>
Sun, 28 Sep 2025 22:40:31 +0000 (15:40 -0700)
In the previous step, we introduced an optional filename that can be
given to a configuration variable, and nullify the fact that such a
configuration setting even existed if the named path is missing or
empty.

Let's do the same for command line options that name a pathname.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/gitcli.adoc
parse-options.c
t/t7500-commit-template-squash-signoff.sh

index 1ea681b59da0aa8015334e402748b459d353d592..ef2a0a399dc97488f8b1b8d5d798703c7c5ee069 100644 (file)
@@ -216,6 +216,20 @@ $ git describe --abbrev=10 HEAD  # correct
 $ git describe --abbrev 10 HEAD  # NOT WHAT YOU MEANT
 ----------------------------
 
+
+Magic filename options
+~~~~~~~~~~~~~~~~~~~~~~
+Options that take a filename allow a prefix `:(optional)`. For example:
+
+----------------------------
+git commit -F :(optional)COMMIT_EDITMSG
+# if COMMIT_EDITMSG does not exist, equivalent to
+git commit
+----------------------------
+
+Like with configuration values, if the named file is missing Git behaves as if
+the option was not given at all. See "Values" in linkgit:git-config[1].
+
 NOTES ON FREQUENTLY CONFUSED OPTIONS
 ------------------------------------
 
index 5224203ffe7bf8a70b4f58060bed20a5dad1afae..4faf66023ac30cecd9b5637687d6a2829571cbfd 100644 (file)
@@ -133,7 +133,6 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
 {
        const char *arg;
        const int unset = flags & OPT_UNSET;
-       int err;
 
        if (unset && p->opt)
                return error(_("%s takes no value"), optname(opt, flags));
@@ -209,21 +208,31 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
        case OPTION_FILENAME:
        {
                const char *value;
-
-               FREE_AND_NULL(*(char **)opt->value);
-
-               err = 0;
+               int is_optional;
 
                if (unset)
                        value = NULL;
                else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
-                       value = (const char *) opt->defval;
-               else
-                       err = get_arg(p, opt, flags, &value);
+                       value = (char *)opt->defval;
+               else {
+                       int err = get_arg(p, opt, flags, &value);
+                       if (err)
+                               return err;
+               }
+               if (!value)
+                       return 0;
 
-               if (!err)
-                       *(char **)opt->value = fix_filename(p->prefix, value);
-               return err;
+               is_optional = skip_prefix(value, ":(optional)", &value);
+               if (!value)
+                       is_optional = 0;
+               value = fix_filename(p->prefix, value);
+               if (is_optional && is_empty_or_missing_file(value)) {
+                       free((char *)value);
+               } else {
+                       FREE_AND_NULL(*(char **)opt->value);
+                       *(const char **)opt->value = value;
+               }
+               return 0;
        }
        case OPTION_CALLBACK:
        {
index 366f7f23b373d5c2a15637bb0365bd323b755036..c065f12baf1baa29721b170edb2a01db6a46a7f4 100755 (executable)
@@ -37,6 +37,16 @@ test_expect_success 'nonexistent template file should return error' '
        )
 '
 
+test_expect_success 'nonexistent optional template file on command line' '
+       echo changes >> foo &&
+       git add foo &&
+       (
+               GIT_EDITOR="echo hello >\"\$1\"" &&
+               export GIT_EDITOR &&
+               git commit --template ":(optional)$PWD/notexist"
+       )
+'
+
 test_expect_success 'nonexistent template file in config should return error' '
        test_config commit.template "$PWD"/notexist &&
        (