* [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter) @ 2007-12-17 18:23 Pierre Habouzit 2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git Here is a series that aims at fixing the various issues with parse-options that were raised recently. * preliminary patch: [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` * teach git parse-options to allow callbacks to ignore arguments that don't seem to be theirs, refactors: [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use. [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well. [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments. * Document this (my previous proposal + Junio's squashed): [PATCH 5/7] parse-options: Add a gitcli(5) man page. * Implement my `{}` proposal, a sed -e s/{}/_/ will replace {} with _ as a wildcard. Contains documentation for this placeholder. [PATCH 6/7] parse-options: have a `use default value` wildcard. * Somehow unrelated patch, but still parse-option related (resend): [PATCH 7/7] git-tag: fix -l switch handling regression. This has been pushed as my ph/parseopt branch on git://git.madism.org/git.git. ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` 2007-12-17 18:23 [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter) Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit 2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit 0 siblings, 2 replies; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- builtin-branch.c | 2 +- builtin-commit.c | 4 ++-- builtin-fast-export.c | 4 ++-- builtin-for-each-ref.c | 2 +- builtin-tag.c | 2 +- parse-options.c | 37 ++++++++++++++++--------------------- parse-options.h | 7 ++++++- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 089cae5..677eee5 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -531,7 +531,7 @@ static void rename_branch(const char *oldname, const char *newname, int force) die("Branch is renamed, but update of config-file failed"); } -static int opt_parse_with_commit(const struct option *opt, const char *arg, int unset) +static int opt_parse_with_commit(const struct option *opt, const char *arg, int flags) { unsigned char sha1[20]; struct commit *commit; diff --git a/builtin-commit.c b/builtin-commit.c index 0a91013..ca18a5c 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -52,10 +52,10 @@ static int no_edit, initial_commit, in_merge; const char *only_include_assumed; struct strbuf message; -static int opt_parse_m(const struct option *opt, const char *arg, int unset) +static int opt_parse_m(const struct option *opt, const char *arg, int flags) { struct strbuf *buf = opt->value; - if (unset) + if (flags & PARSE_OPT_UNSET) strbuf_setlen(buf, 0); else { strbuf_addstr(buf, arg); diff --git a/builtin-fast-export.c b/builtin-fast-export.c index ef27eee..9f914b9 100755 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -26,9 +26,9 @@ static int progress; static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT; static int parse_opt_signed_tag_mode(const struct option *opt, - const char *arg, int unset) + const char *arg, int flags) { - if (unset || !strcmp(arg, "abort")) + if (flags & PARSE_OPT_UNSET || !strcmp(arg, "abort")) signed_tag_mode = ABORT; else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore")) signed_tag_mode = VERBATIM; diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index f36a43c..3eecfe9 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -802,7 +802,7 @@ static struct ref_sort *default_sort(void) return sort; } -int opt_parse_sort(const struct option *opt, const char *arg, int unset) +int opt_parse_sort(const struct option *opt, const char *arg, int flags) { struct ref_sort **sort_tail = opt->value; struct ref_sort *s; diff --git a/builtin-tag.c b/builtin-tag.c index 274901a..fd44b2e 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -348,7 +348,7 @@ struct msg_arg { struct strbuf buf; }; -static int parse_msg_arg(const struct option *opt, const char *arg, int unset) +static int parse_msg_arg(const struct option *opt, const char *arg, int flags) { struct msg_arg *msg = opt->value; diff --git a/parse-options.c b/parse-options.c index e12b428..8f70e5d 100644 --- a/parse-options.c +++ b/parse-options.c @@ -1,9 +1,6 @@ #include "git-compat-util.h" #include "parse-options.h" -#define OPT_SHORT 1 -#define OPT_UNSET 2 - struct optparse_t { const char **argv; int argc; @@ -29,9 +26,9 @@ static inline const char *skip_prefix(const char *str, const char *prefix) static int opterror(const struct option *opt, const char *reason, int flags) { - if (flags & OPT_SHORT) + if (flags & PARSE_OPT_SHORT) return error("switch `%c' %s", opt->short_name, reason); - if (flags & OPT_UNSET) + if (flags & PARSE_OPT_UNSET) return error("option `no-%s' %s", opt->long_name, reason); return error("option `%s' %s", opt->long_name, reason); } @@ -40,14 +37,14 @@ static int get_value(struct optparse_t *p, const struct option *opt, int flags) { const char *s, *arg; - const int unset = flags & OPT_UNSET; + const int unset = flags & PARSE_OPT_UNSET; if (unset && p->opt) return opterror(opt, "takes no value", flags); if (unset && (opt->flags & PARSE_OPT_NONEG)) return opterror(opt, "isn't available", flags); - if (!(flags & OPT_SHORT) && p->opt) { + if (!(flags & PARSE_OPT_SHORT) && p->opt) { switch (opt->type) { case OPTION_CALLBACK: if (!(opt->flags & PARSE_OPT_NOARG)) @@ -99,15 +96,13 @@ static int get_value(struct optparse_t *p, return 0; case OPTION_CALLBACK: - if (unset) - return (*opt->callback)(opt, NULL, 1); - if (opt->flags & PARSE_OPT_NOARG) - return (*opt->callback)(opt, NULL, 0); + if (unset || (opt->flags & PARSE_OPT_NOARG)) + return (*opt->callback)(opt, NULL, flags); if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) - return (*opt->callback)(opt, NULL, 0); + return (*opt->callback)(opt, NULL, flags); if (!arg) return opterror(opt, "requires a value", flags); - return (*opt->callback)(opt, get_arg(p), 0); + return (*opt->callback)(opt, get_arg(p), flags); case OPTION_INTEGER: if (unset) { @@ -135,7 +130,7 @@ static int parse_short_opt(struct optparse_t *p, const struct option *options) for (; options->type != OPTION_END; options++) { if (options->short_name == *p->opt) { p->opt = p->opt[1] ? p->opt + 1 : NULL; - return get_value(p, options, OPT_SHORT); + return get_value(p, options, PARSE_OPT_SHORT); } } return error("unknown switch `%c'", *p->opt); @@ -173,7 +168,7 @@ is_abbreviated: ambiguous_option = abbrev_option; ambiguous_flags = abbrev_flags; } - if (!(flags & OPT_UNSET) && *arg_end) + if (!(flags & PARSE_OPT_UNSET) && *arg_end) p->opt = arg_end + 1; abbrev_option = options; abbrev_flags = flags; @@ -181,13 +176,13 @@ is_abbreviated: } /* negated and abbreviated very much? */ if (!prefixcmp("no-", arg)) { - flags |= OPT_UNSET; + flags |= PARSE_OPT_UNSET; goto is_abbreviated; } /* negated? */ if (strncmp(arg, "no-", 3)) continue; - flags |= OPT_UNSET; + flags |= PARSE_OPT_UNSET; rest = skip_prefix(arg + 3, options->long_name); /* abbreviated and negated? */ if (!rest && !prefixcmp(options->long_name, arg + 3)) @@ -207,9 +202,9 @@ is_abbreviated: return error("Ambiguous option: %s " "(could be --%s%s or --%s%s)", arg, - (ambiguous_flags & OPT_UNSET) ? "no-" : "", + (ambiguous_flags & PARSE_OPT_UNSET) ? "no-" : "", ambiguous_option->long_name, - (abbrev_flags & OPT_UNSET) ? "no-" : "", + (abbrev_flags & PARSE_OPT_UNSET) ? "no-" : "", abbrev_option->long_name); if (abbrev_option) return get_value(p, abbrev_option, abbrev_flags); @@ -351,12 +346,12 @@ void usage_with_options(const char * const *usagestr, /*----- some often used options -----*/ #include "cache.h" -int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) +int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int flags) { int v; if (!arg) { - v = unset ? 0 : DEFAULT_ABBREV; + v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV; } else { v = strtol(arg, (char **)&arg, 10); if (*arg) diff --git a/parse-options.h b/parse-options.h index 102ac31..ae6b3ca 100644 --- a/parse-options.h +++ b/parse-options.h @@ -27,8 +27,13 @@ enum parse_opt_option_flags { PARSE_OPT_HIDDEN = 8, }; +enum parse_opt_cbflags { + PARSE_OPT_SHORT = 1, + PARSE_OPT_UNSET = 2, +}; + struct option; -typedef int parse_opt_cb(const struct option *, const char *arg, int unset); +typedef int parse_opt_cb(const struct option *, const char *arg, int flags); /* * `type`:: -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use. 2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit 2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit 1 sibling, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- parse-options.c | 22 +++++++++++++++------- parse-options.h | 7 +++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/parse-options.c b/parse-options.c index 8f70e5d..d716ccc 100644 --- a/parse-options.c +++ b/parse-options.c @@ -38,7 +38,10 @@ static int get_value(struct optparse_t *p, { const char *s, *arg; const int unset = flags & PARSE_OPT_UNSET; + int may_ign = 0, res; + if (!unset && !p->opt && (opt->flags & PARSE_OPT_OPTARG)) + may_ign = PARSE_OPT_MAY_IGN; if (unset && p->opt) return opterror(opt, "takes no value", flags); if (unset && (opt->flags & PARSE_OPT_NONEG)) @@ -86,7 +89,7 @@ static int get_value(struct optparse_t *p, *(const char **)opt->value = NULL; return 0; } - if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) { + if (may_ign && (!arg || *arg == '-')) { *(const char **)opt->value = (const char *)opt->defval; return 0; } @@ -98,18 +101,23 @@ static int get_value(struct optparse_t *p, case OPTION_CALLBACK: if (unset || (opt->flags & PARSE_OPT_NOARG)) return (*opt->callback)(opt, NULL, flags); - if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) - return (*opt->callback)(opt, NULL, flags); - if (!arg) + if (!may_ign && !arg) return opterror(opt, "requires a value", flags); - return (*opt->callback)(opt, get_arg(p), flags); + if (may_ign && arg && arg[0] == '-' && arg[1]) + return (*opt->callback)(opt, NULL, flags); + res = (*opt->callback)(opt, arg, flags); + if (!may_ign && res == PARSE_OPT_IGNORE) + die("should not happen: MAY_IGN unset, but arg was IGNOREd"); + if (res == PARSE_OPT_IGNORE) + get_arg(p); + return res; case OPTION_INTEGER: if (unset) { *(int *)opt->value = 0; return 0; } - if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) { + if (may_ign && (!arg || !isdigit(*arg))) { *(int *)opt->value = opt->defval; return 0; } @@ -251,7 +259,7 @@ int parse_options(int argc, const char **argv, const struct option *options, usage_with_options_internal(usagestr, options, 1); if (!strcmp(arg + 2, "help")) usage_with_options(usagestr, options); - if (parse_long_opt(&args, arg + 2, options)) + if (parse_long_opt(&args, arg + 2, options) < 0) usage_with_options(usagestr, options); } diff --git a/parse-options.h b/parse-options.h index ae6b3ca..eeb40a4 100644 --- a/parse-options.h +++ b/parse-options.h @@ -27,9 +27,16 @@ enum parse_opt_option_flags { PARSE_OPT_HIDDEN = 8, }; +enum parse_opt_cbres { + PARSE_OPT_ERR = -1, + PARSE_OPT_OK = 0, + PARSE_OPT_IGNORE = 1, +}; + enum parse_opt_cbflags { PARSE_OPT_SHORT = 1, PARSE_OPT_UNSET = 2, + PARSE_OPT_MAY_IGN = 4, }; struct option; -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well. 2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- parse-options.c | 115 ++++++++++++++++++++++++++++--------------------------- 1 files changed, 59 insertions(+), 56 deletions(-) diff --git a/parse-options.c b/parse-options.c index d716ccc..f3f0f2a 100644 --- a/parse-options.c +++ b/parse-options.c @@ -7,15 +7,14 @@ struct optparse_t { const char *opt; }; -static inline const char *get_arg(struct optparse_t *p) +static inline void use_arg(struct optparse_t *p) { if (p->opt) { - const char *res = p->opt; p->opt = NULL; - return res; + } else { + p->argc--; + ++p->argv; } - p->argc--; - return *++p->argv; } static inline const char *skip_prefix(const char *str, const char *prefix) @@ -33,15 +32,62 @@ static int opterror(const struct option *opt, const char *reason, int flags) return error("option `%s' %s", opt->long_name, reason); } +static int parse_opt_string(const struct option *opt, + const char *arg, int flags) +{ + *(const char **)opt->value = flags & PARSE_OPT_UNSET ? NULL : arg; + return 0; +} + +static int parse_opt_integer(const struct option *opt, + const char *arg, int flags) +{ + int v = flags & PARSE_OPT_UNSET ? 0 : opt->defval; + if (arg) { + v = strtol(arg, (char **)&arg, 10); + if (*arg) { + if (flags & PARSE_OPT_MAY_IGN) { + *(int *)opt->value = opt->defval; + return PARSE_OPT_IGNORE; + } + return opterror(opt, "expects a numerical value", 0); + } + } + *(int *)opt->value = v; + return 0; +} + +static int run_callback(struct optparse_t *p, parse_opt_cb *cb, + const struct option *opt, int flags) +{ + const char *arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL); + int may_ign = 0; + + if (!p->opt && (opt->flags & PARSE_OPT_OPTARG)) + may_ign = PARSE_OPT_MAY_IGN; + if ((flags & PARSE_OPT_UNSET) || (opt->flags & PARSE_OPT_NOARG)) + return (*cb)(opt, NULL, flags); + if (!may_ign && !arg) + return opterror(opt, "requires a value", flags); + if (may_ign && arg && arg[0] == '-' && arg[1]) + return (*cb)(opt, NULL, flags); + switch ((*cb)(opt, arg, flags | may_ign)) { + case PARSE_OPT_OK: + use_arg(p); + return PARSE_OPT_OK; + case PARSE_OPT_IGNORE: + if (!may_ign) + die("should not happen: MAY_IGN unset, but arg was IGNOREd"); + return PARSE_OPT_IGNORE; + default: + return PARSE_OPT_ERR; + } +} + static int get_value(struct optparse_t *p, const struct option *opt, int flags) { - const char *s, *arg; const int unset = flags & PARSE_OPT_UNSET; - int may_ign = 0, res; - - if (!unset && !p->opt && (opt->flags & PARSE_OPT_OPTARG)) - may_ign = PARSE_OPT_MAY_IGN; if (unset && p->opt) return opterror(opt, "takes no value", flags); if (unset && (opt->flags & PARSE_OPT_NONEG)) @@ -63,7 +109,6 @@ static int get_value(struct optparse_t *p, } } - arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL); switch (opt->type) { case OPTION_BIT: if (unset) @@ -71,63 +116,21 @@ static int get_value(struct optparse_t *p, else *(int *)opt->value |= opt->defval; return 0; - case OPTION_BOOLEAN: *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; return 0; - case OPTION_SET_INT: *(int *)opt->value = unset ? 0 : opt->defval; return 0; - case OPTION_SET_PTR: *(void **)opt->value = unset ? NULL : (void *)opt->defval; return 0; - case OPTION_STRING: - if (unset) { - *(const char **)opt->value = NULL; - return 0; - } - if (may_ign && (!arg || *arg == '-')) { - *(const char **)opt->value = (const char *)opt->defval; - return 0; - } - if (!arg) - return opterror(opt, "requires a value", flags); - *(const char **)opt->value = get_arg(p); - return 0; - + return run_callback(p, &parse_opt_string, opt, flags); case OPTION_CALLBACK: - if (unset || (opt->flags & PARSE_OPT_NOARG)) - return (*opt->callback)(opt, NULL, flags); - if (!may_ign && !arg) - return opterror(opt, "requires a value", flags); - if (may_ign && arg && arg[0] == '-' && arg[1]) - return (*opt->callback)(opt, NULL, flags); - res = (*opt->callback)(opt, arg, flags); - if (!may_ign && res == PARSE_OPT_IGNORE) - die("should not happen: MAY_IGN unset, but arg was IGNOREd"); - if (res == PARSE_OPT_IGNORE) - get_arg(p); - return res; - + return run_callback(p, opt->callback, opt, flags); case OPTION_INTEGER: - if (unset) { - *(int *)opt->value = 0; - return 0; - } - if (may_ign && (!arg || !isdigit(*arg))) { - *(int *)opt->value = opt->defval; - return 0; - } - if (!arg) - return opterror(opt, "requires a value", flags); - *(int *)opt->value = strtol(get_arg(p), (char **)&s, 10); - if (*s) - return opterror(opt, "expects a numerical value", flags); - return 0; - + return run_callback(p, &parse_opt_integer, opt, flags); default: die("should not happen, someone must be hit on the forehead"); } -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments. 2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- parse-options.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/parse-options.c b/parse-options.c index f3f0f2a..679a963 100644 --- a/parse-options.c +++ b/parse-options.c @@ -359,19 +359,21 @@ void usage_with_options(const char * const *usagestr, int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int flags) { - int v; - - if (!arg) { - v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV; - } else { + int v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV; + if (arg) { v = strtol(arg, (char **)&arg, 10); - if (*arg) + if (*arg) { + if (flags & PARSE_OPT_MAY_IGN) { + *(int *)opt->value = DEFAULT_ABBREV; + return PARSE_OPT_IGNORE; + } return opterror(opt, "expects a numerical value", 0); + } if (v && v < MINIMUM_ABBREV) v = MINIMUM_ABBREV; else if (v > 40) v = 40; } - *(int *)(opt->value) = v; + *(int *)opt->value = v; return 0; } -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/7] parse-options: Add a gitcli(5) man page. 2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit 2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison 0 siblings, 2 replies; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit This page should hold every information about the git ways to parse command lines, and best practices to be used for scripting. Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- Documentation/Makefile | 2 +- Documentation/gitcli.txt | 113 ++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 1 + 3 files changed, 115 insertions(+), 1 deletions(-) create mode 100644 Documentation/gitcli.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index 76df06c..c4486d3 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -2,7 +2,7 @@ MAN1_TXT= \ $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ $(wildcard git-*.txt)) \ gitk.txt -MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt +MAN5_TXT=gitattributes.txt gitignore.txt gitcli.txt gitmodules.txt MAN7_TXT=git.txt MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt new file mode 100644 index 0000000..b7dcf9c --- /dev/null +++ b/Documentation/gitcli.txt @@ -0,0 +1,113 @@ +gitcli(5) +========= + +NAME +---- +gitcli - git command line interface and conventions + +SYNOPSIS +-------- +gitcli + + +DESCRIPTION +----------- + +This manual describes best practice in how to use git CLI. Here are +the rules that you should follow when you are scripting git: + + * it's preferred to use the non dashed form of git commands, which means that + you should prefer `"git foo"` to `"git-foo"`. + + * splitting short options to separate words (prefer `"git foo -a -b"` + to `"git foo -ab"`, the latter may not even work). + + * when a command line option takes an argument, use the 'sticked' form. In + other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short + options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"` + for long options. An option that takes optional option-argument must be + written in the 'sticked' form. + + * when you give a revision parameter to a command, make sure the parameter is + not ambiguous with a name of a file in the work tree. E.g. do not write + `"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work + if you happen to have a file called `HEAD` in the work tree. + + +ENHANCED CLI +------------ +From the git 1.5.4 series and further, many git commands (not all of them at the +time of the writing though) come with an enhanced option parser. + +Here is an exhaustive list of the facilities provided by this option parser. + + +Magic Options +~~~~~~~~~~~~~ +Commands which have the enhanced option parser activated all understand a +couple of magic command line options: + +-h:: + gives a pretty printed usage of the command. ++ +--------------------------------------------- +$ git describe -h +usage: git-describe [options] <committish>* + + --contains find the tag that comes after the commit + --debug debug search strategy on stderr + --all use any ref in .git/refs + --tags use any tag in .git/refs/tags + --abbrev [<n>] use <n> digits to display SHA-1s + --candidates <n> consider <n> most recent tags (default: 10) +--------------------------------------------- + +--help-all:: + Some git commands take options that are only used for plumbing or that + are deprecated, and such options are hidden from the default usage. This + option gives the full list of options. + + +Negating options +~~~~~~~~~~~~~~~~ +Options with long option names can be negated by prefixing `"--no-"`. For +example, `"git branch"` has the option `"--track"` which is 'on' by default. You +can use `"--no-track"` to override that behaviour. The same goes for `"--color"` +and `"--no-color"`. + + +Aggregating short options +~~~~~~~~~~~~~~~~~~~~~~~~~ +Commands that support the enhanced option parser allow you to aggregate short +options. This means that you can for example use `"git rm -rf"` or +`"git clean -fdx"`. + + +Separating argument from the option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You can write the mandatory option parameter to an option as a separate +word on the command line. That means that all the following uses work: + +---------------------------- +$ git foo --long-opt=Arg +$ git foo --long-opt Arg +$ git foo -oArg +$ git foo -o Arg +---------------------------- + +However, this is *NOT* allowed for switches with an optionnal value, where the +'sticked' form must be used: +---------------------------- +$ git describe --abbrev HEAD # correct +$ git describe --abbrev=10 HEAD # correct +$ git describe --abbrev 10 HEAD # NOT WHAT YOU MEANT +---------------------------- + + +Documentation +------------- +Documentation by Pierre Habouzit. + +GIT +--- +Part of the gitlink:git[7] suite diff --git a/Makefile b/Makefile index 7776077..eda7b1a 100644 --- a/Makefile +++ b/Makefile @@ -1172,6 +1172,7 @@ check-docs:: documented,gitattributes | \ documented,gitignore | \ documented,gitmodules | \ + documented,gitcli | \ documented,git-tools | \ sentinel,not,matching,is,ok ) continue ;; \ esac; \ -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/7] parse-options: have a `use default value` wildcard. 2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit 2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison 1 sibling, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- Documentation/gitcli.txt | 20 +++++++++++++++----- parse-options.c | 10 ++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index b7dcf9c..a304072 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -95,14 +95,24 @@ $ git foo -oArg $ git foo -o Arg ---------------------------- -However, this is *NOT* allowed for switches with an optionnal value, where the -'sticked' form must be used: +However, this may become ambiguous for switches with an optional value. The +enhanced option parser provides a placeholder `{}` that tells to the option +parser that it should not try to find an argument to this switch. Though if +you use '{}' sticked to the option, `{}` is passed as the value. ---------------------------- -$ git describe --abbrev HEAD # correct -$ git describe --abbrev=10 HEAD # correct -$ git describe --abbrev 10 HEAD # NOT WHAT YOU MEANT +# all the following uses work +$ git describe --abbrev HEAD +$ git describe --abbrev {} HEAD +$ git describe --abbrev=10 HEAD +$ git describe --abbrev 10 HEAD + +# doesn't work +$ git describe --abbrev={} HEAD ---------------------------- +Note that an optional switch will never try to use the next token as an +argument if it starts with a dash and is not `-`. + Documentation ------------- diff --git a/parse-options.c b/parse-options.c index 679a963..8734bb1 100644 --- a/parse-options.c +++ b/parse-options.c @@ -69,8 +69,14 @@ static int run_callback(struct optparse_t *p, parse_opt_cb *cb, return (*cb)(opt, NULL, flags); if (!may_ign && !arg) return opterror(opt, "requires a value", flags); - if (may_ign && arg && arg[0] == '-' && arg[1]) - return (*cb)(opt, NULL, flags); + if (may_ign && arg) { + if (arg[0] == '-' && arg[1]) + return (*cb)(opt, NULL, flags); + if (!strcmp(arg, "{}")) { + use_arg(p); + return (*cb)(opt, NULL, flags); + } + } switch ((*cb)(opt, arg, flags | may_ign)) { case PARSE_OPT_OK: use_arg(p); -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/7] git-tag: fix -l switch handling regression. 2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit @ 2007-12-17 18:23 ` Pierre Habouzit 2007-12-17 18:56 ` Pierre Habouzit 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw) To: gitster; +Cc: git, Pierre Habouzit Signed-off-by: Pierre Habouzit <madcoder@debian.org> --- builtin-tag.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/builtin-tag.c b/builtin-tag.c index fd44b2e..c7a1563 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -16,7 +16,7 @@ static const char * const git_tag_usage[] = { "git-tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", "git-tag -d <tagname>...", - "git-tag [-n [<num>]] -l [<pattern>]", + "git-tag -l [-n [<num>]] [<pattern>]", "git-tag -v <tagname>...", NULL }; @@ -370,13 +370,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct ref_lock *lock; int annotate = 0, sign = 0, force = 0, lines = 0, - delete = 0, verify = 0; - char *list = NULL, *msgfile = NULL, *keyid = NULL; - const char *no_pattern = "NO_PATTERN"; + list = 0, delete = 0, verify = 0; + char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct option options[] = { - { OPTION_STRING, 'l', NULL, &list, "pattern", "list tag names", - PARSE_OPT_OPTARG, NULL, (intptr_t) no_pattern }, + OPT_INTEGER('l', NULL, &list, "list tag names"), { OPTION_INTEGER, 'n', NULL, &lines, NULL, "print n lines of each tag message", PARSE_OPT_OPTARG, NULL, 1 }, @@ -408,7 +406,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) annotate = 1; if (list) - return list_tags(list == no_pattern ? NULL : list, lines); + return list_tags(argv[0], lines); if (delete) return for_each_tag_name(argv, delete_tag); if (verify) -- 1.5.4.rc0.1148.ga3ab1-dirty ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression. 2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit @ 2007-12-17 18:56 ` Pierre Habouzit 2007-12-17 19:03 ` Pierre Habouzit 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:56 UTC (permalink / raw) To: gitster; +Cc: git [-- Attachment #1: Type: text/plain, Size: 530 bytes --] And I managed to resend the broken version, hurray myself. > + OPT_INTEGER('l', NULL, &list, "list tag names"), OPT_BOOLEAN Both these last minute fixes are applied to my public git.git. Let's now write 1000 times: I will run the test-suite before I send patches, I will rune the test-suite before I send patches, … -- ·O· Pierre Habouzit ··O madcoder@debian.org OOO http://www.madism.org [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression. 2007-12-17 18:56 ` Pierre Habouzit @ 2007-12-17 19:03 ` Pierre Habouzit 2007-12-17 20:13 ` Junio C Hamano 0 siblings, 1 reply; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 19:03 UTC (permalink / raw) To: gitster, git [-- Attachment #1: Type: text/plain, Size: 918 bytes --] On Mon, Dec 17, 2007 at 06:56:52PM +0000, Pierre Habouzit wrote: > And I managed to resend the broken version, hurray myself. > > > + OPT_INTEGER('l', NULL, &list, "list tag names"), > OPT_BOOLEAN > > > > Both these last minute fixes are applied to my public git.git. > > Let's now write 1000 times: I will run the test-suite before I send > patches, I will rune the test-suite before I send patches, … oh and t7004 doesn't pass anymore because of the: git -n xxx -l or git -n "" -l tests. If we really want to allow that (but it _REALLY_ feels wrong to me) we have to make '-l' a callback that groks non integers as 0. Else the test also has to be fixed, I'm not sure what to do here. -- ·O· Pierre Habouzit ··O madcoder@debian.org OOO http://www.madism.org [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression. 2007-12-17 19:03 ` Pierre Habouzit @ 2007-12-17 20:13 ` Junio C Hamano 0 siblings, 0 replies; 13+ messages in thread From: Junio C Hamano @ 2007-12-17 20:13 UTC (permalink / raw) To: Pierre Habouzit; +Cc: git Pierre Habouzit <madcoder@debian.org> writes: > On Mon, Dec 17, 2007 at 06:56:52PM +0000, Pierre Habouzit wrote: >> And I managed to resend the broken version, hurray myself. >> >> > + OPT_INTEGER('l', NULL, &list, "list tag names"), >> OPT_BOOLEAN >> >> >> >> Both these last minute fixes are applied to my public git.git. >> >> Let's now write 1000 times: I will run the test-suite before I send >> patches, I will rune the test-suite before I send patches, … > > oh and t7004 doesn't pass anymore because of the: > > git -n xxx -l or git -n "" -l tests. If we really want to allow that > (but it _REALLY_ feels wrong to me) we have to make '-l' a callback that > groks non integers as 0. Else the test also has to be fixed, I'm not > sure what to do here. I did not understand what "git tag -n xxx" was meant to do, either. Time to run blame and ask the responsible party? I suspect "-n ''" there might be meant as a way to spell the "no argument here -- use our default" instruction. It looks slightly nicer than that '{}' but not quite. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/7] parse-options: Add a gitcli(5) man page. 2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit 2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit @ 2007-12-18 2:00 ` Wayne Davison 1 sibling, 0 replies; 13+ messages in thread From: Wayne Davison @ 2007-12-18 2:00 UTC (permalink / raw) To: Pierre Habouzit; +Cc: git On Mon, Dec 17, 2007 at 07:23:15PM +0100, Pierre Habouzit wrote: > + * when a command line option takes an argument, use the 'sticked' form. A minor issue: the word "sticked" reads very strangely to me (in this spot and several others in your text). I think something like joined or attached (or even abutted) would be better, as seen in this altered text for the spot cited above (with a few other improvements thrown in): * when a command line option takes an argument, it is best to use the 'joined' form. In other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"` for long options. If an option takes an optional option-argument, it MUST be written using the 'joined' form when providing the option-argument. ..wayne.. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` 2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit @ 2007-12-17 18:54 ` Pierre Habouzit 1 sibling, 0 replies; 13+ messages in thread From: Pierre Habouzit @ 2007-12-17 18:54 UTC (permalink / raw) To: gitster; +Cc: git [-- Attachment #1: Type: text/plain, Size: 774 bytes --] And of course here is the MadBug #1, to be squashed: --- builtin-rev-parse.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 20d1789..3e8ee62 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -210,10 +210,10 @@ static int try_difference(const char *arg) return 0; } -static int parseopt_dump(const struct option *o, const char *arg, int unset) +static int parseopt_dump(const struct option *o, const char *arg, int flags) { struct strbuf *parsed = o->value; - if (unset) + if (flags & PARSE_OPT_UNSET) strbuf_addf(parsed, " --no-%s", o->long_name); else if (o->short_name) strbuf_addf(parsed, " -%c", o->short_name); -- 1.5.4.rc0.1151.g102b0 [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2007-12-18 2:01 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-12-17 18:23 [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter) Pierre Habouzit 2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit 2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit 2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit 2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit 2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit 2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit 2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit 2007-12-17 18:56 ` Pierre Habouzit 2007-12-17 19:03 ` Pierre Habouzit 2007-12-17 20:13 ` Junio C Hamano 2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison 2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).