From 43f61f9f67c00e02723790198a68a1ac9348008d Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 12 Oct 2026 13:48:27 -0400 Subject: [PATCH 1/5] completion: simplify stash subcommand completion The stash completion helper contains a hard-coded list of commands, but git-stash provides a mechanism to list such commands (--git-completion-helper). The pattern for using it is wrapped by __git_resolve_builtins, so use it, bring _git_stash closer in line with other completion helpers. Note that we maintain the "save" special case, since it was removed from default completion in 0eb5a4f911 (completion: stop showing 'save' for stash by default, 2018-04-20). We don't have to do anything special with the exclude (3rd) argument to __git_resolve_builtins, though, because save is already marked PARSE_OPT_NOCOMPLETE. Signed-off-by: D. Ben Knoble Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c3a49e2e22..d60e85479c 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3553,8 +3553,12 @@ _git_sparse_checkout () _git_stash () { - local subcommands='push list show apply clear drop pop create branch import export' - local subcommand="$(__git_find_on_cmdline "$subcommands save")" + local subcommands subcommand + + __git_resolve_builtins stash + + subcommands="$___git_resolved_builtins" + subcommand="$(__git_find_on_cmdline "$subcommands save")" if [ -z "$subcommand" ]; then case "$((cword - __git_cmd_idx)),$cur" in From 4ee00faa9d8960d3e457a19723921bf2173d4d72 Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 12 Oct 2026 13:48:28 -0400 Subject: [PATCH 2/5] completion: extract common stash listing code With no change in behavior, prepare to adjust how stashes are completed by centralizing candidate generation. Signed-off-by: D. Ben Knoble Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d60e85479c..697fef5462 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3593,20 +3593,23 @@ _git_stash () if [ $cword -eq $((__git_cmd_idx+2)) ]; then __git_complete_refs else - __gitcomp_nl "$(__git stash list \ - | sed -n -e 's/:.*//p')" + __git_complete_stashes fi ;; import,*) __git_complete_refs ;; show,*|apply,*|drop,*|pop,*|export,*) - __gitcomp_nl "$(__git stash list \ - | sed -n -e 's/:.*//p')" + __git_complete_stashes ;; esac } +__git_complete_stashes () +{ + __gitcomp_nl "$(__git stash list | sed -n -e 's/:.*//p')" +} + _git_submodule () { __git_has_doubledash && return From f4ced7cb0b0f552df39fc2b0a70418941a134385 Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 12 Oct 2026 13:48:29 -0400 Subject: [PATCH 3/5] completion: fix Zsh handling of stash names When Git completes stashes for Zsh, it eventually invokes something like this (via our redefinition of __gitcomp_nl): compadd -Q -S " " -p "" -- 'stash@{0}' 'stash@{1}' && _ret=0 Because of -Q, the braces are unquoted, and Zsh will leave us at (for example) git stash show stash@{ cursor ^ >From here, the list-choices widget (on Ctrl-D by default) will show stash@{0} and stash@{1}, but the complete-word widget (Tab) will just add another brace. Zsh things we're trying to do a brace expansion, I think! Interestingly, using menu-complete (Ctrl-N) does cycle through matches, since it's taking a slightly different completion path in Zsh. We might try to fix this by passing surrounding single quotes (using the -S/-p arguments of compadd, which we can do via __gitcomp_nl's other parameters), and indeed Zsh will generate git stash show 'stash@{ cursor ^ but completing here won't find anything, and I'm not totally sure why. Instead, though, we can let Zsh quote metacharacters (removing -Q) and everything "just works." It changes the output format a bit (users see stash@\{0\}, for example), but I find this an improvement over not being able to complete names at all. menu-complete is unchanged aside from the extra backslashes. So, override stash listing completion in Zsh with a working version. Signed-off-by: D. Ben Knoble Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.zsh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index d5c526665b..2aea7770d2 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -135,6 +135,11 @@ __gitcomp_file_direct () __gitcomp_file "$1" "" } +__git_complete_stashes () +{ + compadd -S ' ' -- ${(f)"$(__git stash list | sed -n -e 's/:.*//p')"} && _ret=0 +} + _git_zsh () { __gitcomp "v1.1" From f4c8d30a74dc762872388c18408a694d22207560 Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 12 Oct 2026 13:48:30 -0400 Subject: [PATCH 4/5] doc: drop usage mentions of "git stash save" Even though we previously deprecated it in fd2ebf14db (stash: mark "git stash save" deprecated in the man page, 2017-10-22), the save subcommand clings to life. For example, 951ec747d4 (doc txt & -h consistency: make "stash" consistent, 2022-10-13) brought back "save" to the git-stash(1) synopsis, and 41a28eb6c1 (stash: implement '--staged' option for 'push' and 'save', 2021-10-18) gave it new options. But we really discourage its use in modern Git, so let's drop mention of it from -h usage and the synopsis. It's still described in the manual, since some descriptions talk about the "save" command. As we haven't gone ahead with a full deprecation and removal, we can leave these pieces for folks whose fingers still type "save" and need a reference for its behavior. Signed-off-by: D. Ben Knoble Signed-off-by: Junio C Hamano --- Documentation/git-stash.adoc | 2 -- builtin/stash.c | 1 - 2 files changed, 3 deletions(-) diff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc index d6e8c4144c..6bf510702b 100644 --- a/Documentation/git-stash.adoc +++ b/Documentation/git-stash.adoc @@ -18,8 +18,6 @@ git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | - [-u | --include-untracked] [-a | --all] [(-m | --message) ] [--pathspec-from-file= [--pathspec-file-nul]] [--] [...] -git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet] - [-u | --include-untracked] [-a | --all] [] git stash clear git stash create [] git stash store [(-m | --message) ] [-q | --quiet] diff --git a/builtin/stash.c b/builtin/stash.c index 7a9843413b..94869c2429 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -75,7 +75,6 @@ static const char * const git_stash_usage[] = { BUILTIN_STASH_APPLY_USAGE, BUILTIN_STASH_BRANCH_USAGE, BUILTIN_STASH_PUSH_USAGE, - BUILTIN_STASH_SAVE_USAGE, BUILTIN_STASH_CLEAR_USAGE, BUILTIN_STASH_CREATE_USAGE, BUILTIN_STASH_STORE_USAGE, From 7a7f8f8d87b13fccbfd2c02463a3fd314545f870 Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 12 Oct 2026 13:48:31 -0400 Subject: [PATCH 5/5] completion: drop "stash save" completion altogether It's been deprecated since fd2ebf14db (stash: mark "git stash save" deprecated in the man page, 2017-10-22) and the previous commit removed further documentation suggesting to use it. Since we recommend push instead, stop completing for "save" and remove a special case in completion code. Signed-off-by: D. Ben Knoble Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 697fef5462..9cd9c7cadb 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3558,16 +3558,13 @@ _git_stash () __git_resolve_builtins stash subcommands="$___git_resolved_builtins" - subcommand="$(__git_find_on_cmdline "$subcommands save")" + subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then case "$((cword - __git_cmd_idx)),$cur" in *,--*) __gitcomp_builtin stash_push ;; - 1,sa*) - __gitcomp "save" - ;; 1,*) __gitcomp "$subcommands" ;;