[PATCH v5 1/8] git: add `deprecated` category to --list-cmds
- From
- kristofferhaugsbakk@fastmail.com <kristofferhaugsbakk@fastmail.com>
- Date
- Sep 14, 2025, 19:49 UTC
- Message-ID
- <13682553018470845b4b000f0c5fbdac0539c8e3.1757879060.git.code@khaugsbakk.name>
- In-Reply-To
- <cover.1757879060.git.code@khaugsbakk.name>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
With 145 builtin commands (according to `git --list-cmds=builtins`), users are probably not keeping on top of which ones (if any) are deprecated.
Let’s expand the experimental `--list-cmds`[1] to allow users and programs to query for this information. We will also use this in an upcoming commit to implement `is_deprecated_command`.
[1]: Using something which is experimental to query for deprecations is
perhaps not the most ideal approach, but it is simple to implement
and better than having to scan the documentationAcked-by: Patrick Steinhardt <ps@pks.im> Helped-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> ---
Notes (series):
v5:
Add back the `BUG` check from v3 because I think it makes sense to only
populate one of the two options.
Link: https://lore.kernel.org/git/cover.1757345711.git.code@khaugsbakk.name/T/#m922b852384911511c45afd458051f52b50dce62f
v4:
Incorporate Patrick’s suggestions about the for-loop refactor and
formatting the overlong lines. Now drop the function doc since it
doesn’t apply anymore.
Also adjust the commit message now that we use it in the C source in an
upcoming commit, not just/only as an assert-helper (in an upcoming
commit).
v3 (new):
This is something I wanted to submit independently until the point about
aliasing builtins was brought up.[1] It will help (in a small way) with
the upcoming patch “git: allow alias-shadowing deprecated builtins”.
By the way: should `command-list.txt` be updated in some way (I didn’t
know what way?)
🔗 1: https://lore.kernel.org/git/cover.1756311355.git.code@khaugsbakk.name/T/#mee19f8d39572f9021f9d3000758e87b6c32c967cDocumentation/git.adoc | 3 ++- git.c | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/Documentation/git.adoc b/Documentation/git.adoc index 743b7b00e4d..a2f0838b168 100644 --- a/Documentation/git.adoc +++ b/Documentation/git.adoc @@ -219,7 +219,8 @@ If you just want to run git as if it was started in `<path>` then use List commands by group. This is an internal/experimental option and may change or be removed in the future. Supported groups are: builtins, parseopt (builtin commands that use - parse-options), main (all commands in libexec directory), + parse-options), deprecated (deprecated builtins), + main (all commands in libexec directory), others (all other commands in `$PATH` that have git- prefix), list-<category> (see categories in command-list.txt), nohelpers (exclude helper commands), alias and config diff --git a/git.c b/git.c index 83eac0aeab7..511efdf2056 100644 --- a/git.c +++ b/git.c @@ -28,6 +28,7 @@ #define NEED_WORK_TREE (1<<3) #define DELAY_PAGER_CONFIG (1<<4) #define NO_PARSEOPT (1<<5) /* parse-options is not used */ +#define DEPRECATED (1<<6) struct cmd_struct { const char *cmd; @@ -51,7 +52,9 @@ const char git_more_info_string[] = static int use_pager = -1; -static void list_builtins(struct string_list *list, unsigned int exclude_option); +static void list_builtins(struct string_list *list, + unsigned int include_option, + unsigned int exclude_option); static void exclude_helpers_from_list(struct string_list *list) { @@ -88,7 +91,7 @@ static int list_cmds(const char *spec) int len = sep - spec; if (match_token(spec, len, "builtins")) - list_builtins(&list, 0); + list_builtins(&list, 0, 0); else if (match_token(spec, len, "main")) list_all_main_cmds(&list); else if (match_token(spec, len, "others")) @@ -99,6 +102,8 @@ static int list_cmds(const char *spec) list_aliases(&list); else if (match_token(spec, len, "config")) list_cmds_by_config(&list); + else if (match_token(spec, len, "deprecated")) + list_builtins(&list, DEPRECATED, 0); else if (len > 5 && !strncmp(spec, "list-", 5)) { struct strbuf sb = STRBUF_INIT; @@ -322,7 +327,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) if (!strcmp(cmd, "parseopt")) { struct string_list list = STRING_LIST_INIT_DUP; - list_builtins(&list, NO_PARSEOPT); + list_builtins(&list, 0, NO_PARSEOPT); for (size_t i = 0; i < list.nr; i++) printf("%s ", list.items[i].string); string_list_clear(&list, 0); @@ -590,7 +595,7 @@ static struct cmd_struct commands[] = { { "notes", cmd_notes, RUN_SETUP }, { "pack-objects", cmd_pack_objects, RUN_SETUP }, #ifndef WITH_BREAKING_CHANGES - { "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT }, + { "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT | DEPRECATED }, #endif { "pack-refs", cmd_pack_refs, RUN_SETUP }, { "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT }, @@ -647,7 +652,7 @@ static struct cmd_struct commands[] = { { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, #ifndef WITH_BREAKING_CHANGES - { "whatchanged", cmd_whatchanged, RUN_SETUP }, + { "whatchanged", cmd_whatchanged, RUN_SETUP | DEPRECATED }, #endif { "worktree", cmd_worktree, RUN_SETUP }, { "write-tree", cmd_write_tree, RUN_SETUP }, @@ -668,11 +673,16 @@ int is_builtin(const char *s) return !!get_builtin(s); } -static void list_builtins(struct string_list *out, unsigned int exclude_option) +static void list_builtins(struct string_list *out, + unsigned int include_option, + unsigned int exclude_option) { + if (include_option && exclude_option) + BUG("'include_option' and 'exclude_option' are mutually exclusive"); for (size_t i = 0; i < ARRAY_SIZE(commands); i++) { - if (exclude_option && - (commands[i].option & exclude_option)) + if (include_option && !(commands[i].option & include_option)) + continue; + if (exclude_option && (commands[i].option & exclude_option)) continue; string_list_append(out, commands[i].cmd); }
-- 2.51.0.16.gcd94ab5bf81