stash completion miscellany
cover stash completion miscellany
Hi all,
This short patch series takes care of a few paper cuts in stash completion. The first patch is a small code cleanup I noticed a while back while working on bfc1b34859 (completion: add stash import, export, 2026-02-07), I think. The next 2 take care of a problem I've been having with Zsh's completion of stashes (cf. Unix & Linux SE [1]).
[1]: https://unix.stackexchange.com/q/807580/301073
The final 2 are not only about completion; I noticed we were special-casing save completion, did some digging, and was a bit confused by the status of "git stash save". So, I figured while I was here I would start a conversation about (a) restoring the git-stash(1) manual to it's "no save" version and (b) ripping out the special case.
These last 2 may be controversial, and I'm not particularly attached to them, so if they need to be dropped I won't really complain. OTOH, what's the point of a deprecated subcommand we still advertise? ;)
Generated-with: git format-patch @{u}.. -o p
[1/5] completion: simplify stash subcommand completion [2/5] completion: extract common stash listing code [3/5] completion: fix Zsh handling of stash names [4/5] doc: drop usage mentions of "git stash save" [5/5] completion: drop "stash save" completion altogether
Documentation/git-stash.adoc | 2 -- builtin/stash.c | 1 - contrib/completion/git-completion.bash | 22 +++++++++++++--------- contrib/completion/git-completion.zsh | 5 +++++ 4 files changed, 18 insertions(+), 12 deletions(-)
base-commit: 6de20f6092dcf9bdb1c8efe03db4b70c82b423dd
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
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.
--- contrib/completion/git-completion.bash | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
contrib/completion/git-completion.bash +6 -2
@@ -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
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
Re: [PATCH 1/5] completion: simplify stash subcommand completion
Quoted 4 lines · D. Ben Knoble
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_stashcloser in line with
s/bring/bringing/?
Quoted 7 lines
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 markedPARSE_OPT_NOCOMPLETE.
I didn't understand the last sentence without going into the code.
I assume what you want to say is that we don't have to explicitly exclude it when completing the subcommand because it's already marked as NOCOMPLETE. But we don't want to fully ignore it, either, because we want to be able to complete that subcommand if the user explicitly wrote it?
So basically: we're not completing it if the user writes "git stash sa<TAB>", but we then know to complete its options if the user writes "git stash save --<TAB>". Which I guess makes sense for a deprecated subcommand.
Quoted 6 lines
contrib/completion/git-completion.bash +0
-0@@ -3553,8 +3553,12 @@ _git_sparse_checkout ()
contrib/completion/git-completion.bash _git_sparse_checkout () · line 3561
Quoted 10 lines
contrib/completion/git-completion.bash +6
-2_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")"
More plumbing, but less stuff that we need to keep up-to-date. This also fixes that the "store" subcommand wasn't completed, which should probably be pointed out in the commit message.
Patrick
Re: [PATCH 1/5] completion: simplify stash subcommand completion
Quoted 10 lines · Patrick Steinhardt
Quoted 4 lines · D. Ben Knoble
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_stashcloser in line withs/bring/bringing/?
Will fix!
Quoted 16 lines
Quoted 7 lines
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 markedPARSE_OPT_NOCOMPLETE.I didn't understand the last sentence without going into the code.
I assume what you want to say is that we don't have to explicitly exclude it when completing the subcommand because it's already marked as NOCOMPLETE. But we don't want to fully ignore it, either, because we want to be able to complete that subcommand if the user explicitly wrote it?
Quoted 4 lines
So basically: we're not completing it if the user writes "git stash sa<TAB>", but we then know to complete its options if the user writes "git stash save --<TAB>". Which I guess makes sense for a deprecated subcommand.
Correct. I got a little too familiar with the completion guts while working on this. I’ll try reworking it when I get back to v2.
Quoted 6 lines
Quoted 6 lines
contrib/completion/git-completion.bash +0
-0@@ -3553,8 +3553,12 @@ _git_sparse_checkout ()
Quoted 12 lines
contrib/completion/git-completion.bash _git_sparse_checkout () · line 3561
Quoted 10 lines
contrib/completion/git-completion.bash +6
-2_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")"More plumbing, but less stuff that we need to keep up-to-date.
And more aligned with other helpers, yep.
Quoted 3 lines
This also
fixes that the "store" subcommand wasn't completed, which should probably be pointed out in the commit message.
I missed that, will add. Thanks!
PATCH 2/5 completion: extract common stash listing code
In reply to D. Ben KnobleWith no change in behavior, prepare to adjust how stashes are completed by centralizing candidate generation.
--- contrib/completion/git-completion.bash | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
contrib/completion/git-completion.bash +7 -4
@@ -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
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
PATCH 3/5 completion: fix Zsh handling of stash names
In reply to D. Ben KnobleWhen 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=0Because 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.
--- contrib/completion/git-completion.zsh | 5 +++++ 1 file changed, 5 insertions(+)
contrib/completion/git-completion.zsh +5 -0
@@ -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"
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
Re: [PATCH 3/5] completion: fix Zsh handling of stash names
Quoted 8 lines · D. Ben Knoble
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=0Because of -Q, the braces are unquoted, and Zsh will leave us at (for example)
Quoted 6 lines
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
s/things/thinks/
Quoted 12 lines
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.
Quoted 7 lines
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.
Hm. I assume you tried finding a variant that works for both Bash and Zsh so that we don't have to carry this override?
contrib/completion/git-completion.zsh __gitcomp_file_direct () · line 141
Quoted 12 lines
contrib/completion/git-completion.zsh +4
-0@@ -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 +}
Patrick
Re: [PATCH 3/5] completion: fix Zsh handling of stash names
Quoted 12 lines · Patrick Steinhardt
Quoted 8 lines · D. Ben Knoble
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=0Because of -Q, the braces are unquoted, and Zsh will leave us at (for example)
Quoted 8 lines
Quoted 6 lines
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
s/things/thinks/
Will fix!
Quoted 18 lines
Quoted 18 lines
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.
Quoted 4 lines
Quoted 1 line
So, override stash listing completion in Zsh with a working version.
Hm. I assume you tried finding a variant that works for both Bash and Zsh so that we don't have to carry this override?
Actually, no. I assumed Bash was working and haven’t tested it either way. Presumably we’d have a report from someone if it were doing what Zsh does?
Many Zsh users, OTOH, use the Zsh-distributed completions, which stackoverflow for me (and anyway I prefer ours).
I won’t have time to see if Bash is also Brien here, but this shouldn’t change Bash’s behavior at least.
Oh, re-reading: yes, I looked for something that was compatible with existing code. I mentioned one such attempt (single quotes). No luck, though.
PATCH 4/5 doc: drop usage mentions of "git stash save"
In reply to D. Ben KnobleEven 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.
---
Notes (benknoble/commits):
AFAICT there was no discussion of its deprecation when re-adding save to the documentation, so I wonder if that was just an oversight.
Documentation/git-stash.adoc | 2 -- builtin/stash.c | 1 - 2 files changed, 3 deletions(-)
Documentation/git-stash.adoc +0 -2
@@ -18,8 +18,6 @@ git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | - [-u | --include-untracked] [-a | --all] [(-m | --message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...] -git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet] - [-u | --include-untracked] [-a | --all] [<message>] git stash clear git stash create [<message>] git stash store [(-m | --message) <message>] [-q | --quiet] <commit>
builtin/stash.c +0 -1
@@ -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,
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
Re: [PATCH 4/5] doc: drop usage mentions of "git stash save"
Quoted 3 lines · D. Ben Knoble
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
Heh :)
Quoted 10 lines
"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.
I was wondering why we still have the command as part of our synopsis in case it's deprecated, so good that you address this, too.
Quoted 6 lines
Signed-off-by D. Ben Knoble <[email protected]>---
Notes (benknoble/commits):
AFAICT there was no discussion of its deprecation when re-adding save to the documentation, so I wonder if that was just an oversight.
I bet. In any case, I agree with removing it from our synopsis again.
Patrick
PATCH 5/5 completion: drop "stash save" completion altogether
In reply to D. Ben KnobleIt'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.
--- contrib/completion/git-completion.bash | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
contrib/completion/git-completion.bash +1 -4
@@ -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" ;;
Signature · 1 line
2.56.0.184.g5a00b4a6e9.dirty
Re: [PATCH 5/5] completion: drop "stash save" completion altogether
Quoted 6 lines · D. Ben Knoble
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.
This is the only part I'm a bit torn on. I think it's reasonable to not autocomplete the "save" command, but if the user manually types it, should we really stop autocompleting its options altogether?
Maybe the answer is "yes". After all, as you mentioned in the preceding commit, the command is deprecated since 2017 already! And after almost 10 years I think it's fair to start giving users more nudges into the direction of using "push" instead.
One note though: the command _will_ be completed in the case where you have GIT_COMPLETION_SHOW_ALL set.
Patrick
Re: [PATCH 5/5] completion: drop "stash save" completion altogether
Quoted 15 lines · Patrick Steinhardt
Quoted 6 lines · D. Ben Knoble
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.
This is the only part I'm a bit torn on. I think it's reasonable to not autocomplete the "save" command, but if the user manually types it, should we really stop autocompleting its options altogether?
Quoted 7 lines
Maybe the answer is "yes". After all, as you mentioned in the preceding commit, the command is deprecated since 2017 already! And after almost 10 years I think it's fair to start giving users more nudges into the direction of using "push" instead.
One note though: the command _will_ be completed in the case where you have
GIT_COMPLETION_SHOW_ALLset
I should definitely mention SHOW_ALL; I’m not actually sure what happens for « git stash save --<TAB> » with this patch, so I’ll double-check. I actually wonder if it will complete options.
Would that satisfy you if so ?
Re: [PATCH 5/5] completion: drop "stash save" completion altogether
Quoted 20 lines · Ben Knoble
Quoted 20 lines · Patrick Steinhardt
Quoted 6 lines · D. Ben Knoble
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.
This is the only part I'm a bit torn on. I think it's reasonable to not autocomplete the "save" command, but if the user manually types it, should we really stop autocompleting its options altogether?
Maybe the answer is "yes". After all, as you mentioned in the preceding commit, the command is deprecated since 2017 already! And after almost 10 years I think it's fair to start giving users more nudges into the direction of using "push" instead.
Quoted 8 lines
Quoted 2 lines
One note though: the command _will_ be completed in the case where you have
GIT_COMPLETION_SHOW_ALLsetI should definitely mention
SHOW_ALL; I’m not actually sure what happens for « git stash save --<TAB> » with this patch, so I’ll double-check. I actually wonder if it will complete options.Would that satisfy you if so ?
Probably depends on the outcome of your tests, but ultimately I think I'd be fine with either of the options. But if we stop autocompleting we should definitely mention SHOW_ALL.
Thanks!
Patrick
Re: [PATCH 5/5] completion: drop "stash save" completion altogether
Quoted 29 lines · Patrick Steinhardt
Quoted 27 lines · Ben Knoble
Quoted 15 lines · Patrick Steinhardt
Quoted 6 lines · D. Ben Knoble
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.
This is the only part I'm a bit torn on. I think it's reasonable to not autocomplete the "save" command, but if the user manually types it, should we really stop autocompleting its options altogether?
Quoted 7 lines
Maybe the answer is "yes". After all, as you mentioned in the preceding commit, the command is deprecated since 2017 already! And after almost 10 years I think it's fair to start giving users more nudges into the direction of using "push" instead.
One note though: the command _will_ be completed in the case where you have
GIT_COMPLETION_SHOW_ALLsetI should definitely mention
SHOW_ALL; I’m not actually sure what happens for « git stash save --<TAB> » with this patch, so I’ll double-check. I actually wonder if it will complete options.
Quoted 5 lines
Quoted 1 line
Would that satisfy you if so ?
Probably depends on the outcome of your tests, but ultimately I think I'd be fine with either of the options. But if we stop autocompleting we should definitely mention
SHOW_ALL.
Here's what my testing showed (all Zsh):
- with SHOW_ALL, "git stash <tab>" lists "save" as an option; "git stash save --<tab>" completes options
- without SHOW_ALL, "git stash <tab>" does not list "save"; "git stash sa<tab>" does not complete "save"; "git stash save --<tab>" completes options
I'll update the commit locally to reflect this. Thoughts?
Signature · 1 line
D. Ben Knoble
Re: [PATCH 5/5] completion: drop "stash save" completion altogether
Quoted 38 lines · D. Ben Knoble
Quoted 29 lines · Patrick Steinhardt
Quoted 27 lines · Ben Knoble
Quoted 15 lines · Patrick Steinhardt
Quoted 6 lines · D. Ben Knoble
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.
This is the only part I'm a bit torn on. I think it's reasonable to not autocomplete the "save" command, but if the user manually types it, should we really stop autocompleting its options altogether?
Quoted 7 lines
Maybe the answer is "yes". After all, as you mentioned in the preceding commit, the command is deprecated since 2017 already! And after almost 10 years I think it's fair to start giving users more nudges into the direction of using "push" instead.
One note though: the command _will_ be completed in the case where you have
GIT_COMPLETION_SHOW_ALLsetI should definitely mention
SHOW_ALL; I’m not actually sure what happens for « git stash save --<TAB> » with this patch, so I’ll double-check. I actually wonder if it will complete options.Quoted 5 lines
Quoted 1 line
Would that satisfy you if so ?
Probably depends on the outcome of your tests, but ultimately I think I'd be fine with either of the options. But if we stop autocompleting we should definitely mention
SHOW_ALL.Here's what my testing showed (all Zsh):
Quoted 7 lines
- with
SHOW_ALL, "git stash <tab>" lists "save" as an option; "git stash save --<tab>" completes options
- withoutSHOW_ALL, "git stash <tab>" does not list "save"; "git stash sa<tab>" does not complete "save"; "git stash save --<tab>" completes optionsI'll update the commit locally to reflect this. Thoughts?
We could of course add logic to explicitly stop completing options for the deprecated subcommand. But I doubt it's worth it? So I think this is good enough.
Patrick
v2 cover stash completion miscellany
In reply to D. Ben KnobleHi all,
This short patch series takes care of a few paper cuts in stash completion. The first patch is a small code cleanup I noticed a while back while working on bfc1b34859 (completion: add stash import, export, 2026-02-07), I think. The next 2 take care of a problem I've been having with Zsh's completion of stashes (cf. Unix & Linux SE [1]).
[1]: https://unix.stackexchange.com/q/807580/301073
Changes in v2:
• Reworded a few commit messages thanks to Patrick
• Clarify the behavior of the final patches with completion for "git stash save" (also thanks to Patrick)
The final 2 are not only about completion; I noticed we were special-casing save completion, did some digging, and was a bit confused by the status of "git stash save". So, I figured while I was here I would start a conversation about (a) restoring the git-stash(1) manual to it's "no save" version and (b) ripping out the special case.
These last 2 may be controversial, and I'm not particularly attached to them, so if they need to be dropped I won't really complain. OTOH, what's the point of a deprecated subcommand we still advertise? ;)
Generated-with: git format-patch @{u}.. -o p -v2 --range-diff=@{u}..d1d0bf2d9a7d380d10771b5d1bceb8db91c5f05e [email protected] --cc='Patrick Steinhardt <[email protected]>'
I accidentally left the above line in v1, but I'm considering leaving it in from now on? It's the exact command I run to generate patches; I store it as a "trailer" in the branch description, then run "git generated-with"† which (effectively) does
eval "$(git bdesc | git interpret-trailers --parse | grep ^Generated-with | cut -d: -f 2-)"
where "bdesc" is an alias for
git -c core.editor=cat branch --edit-description | git stripspace -s
Anyway, I've been hand-editing them out of cover letters for the last few series, but if it doesn't bother anyone I'll just leave it around. Might be helpful for new folks learning how to format patches?
†: https://github.com/benknoble/Dotfiles/blob/master/links/bin/git-generated-with
[1/5] completion: simplify stash subcommand completion [2/5] Completion: extract common stash listing code [3/5] completion: fix Zsh handling of stash names [4/5] doc: drop usage mentions of "git stash save" [5/5] completion: drop "stash save" completion altogether
Documentation/git-stash.adoc | 2 -- builtin/stash.c | 1 - contrib/completion/git-completion.bash | 22 +++++++++++++--------- contrib/completion/git-completion.zsh | 5 +++++ 4 files changed, 18 insertions(+), 12 deletions(-)
Diff-intervalle contre v1 :
1: d0e461a14a ! 1: 90d36b6445 completion: simplify stash subcommand completion
@@ Commit message
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.
+ __git_resolve_builtins, so use it, bringing _git_stash closer in line
+ with other completion helpers. As a nice side-benefit, this also adds
+ "store" subcommand completion, which is missing from the explicit list
+ of subcommands.
- Note that we maintain the "save" special case, since it was removed from
+ 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.
+ stash by default, 2018-04-20). One might think we need to give "save" to
+ __git_resolve_builtins' 3rd exclude argument to prevent it from
+ showing up, but we don't: "save" is already marked PARSE_OPT_NOCOMPLETE.
+
+ †We don't complete the "save" subcommand unless at least "sa" has been
+ typed, but we do complete its options if explicitly typed. With this
+ change, we will complete "save" if GIT_COMPLETION_SHOW_ALL=1.
## contrib/completion/git-completion.bash ##
@@ contrib/completion/git-completion.bash: _git_sparse_checkout ()
2: 6c24a833fc = 2: abf8efb792 Completion: extract common stash listing code 3: 22283a1d5f ! 3: f4f6b89ff6 completion: fix Zsh handling of stash names
@@ Commit message
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
+ add another brace. Zsh thinks 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
+ -S/-p arguments of compadd, which we can do from Bash in our code via
+ __gitcomp_nl's other parameters), and indeed Zsh will generate
git stash show 'stash@{
cursor ^
4: 985a14f18e = 4: 3762f9d5bb doc: drop usage mentions of "git stash save" 5: d1d0bf2d9a ! 5: 0266646fb4 completion: drop "stash save" completion altogether
@@ Commit message
further documentation suggesting to use it.
Since we recommend push instead, stop completing for "save" and remove a
- special case in completion code.
+ special case in completion code. It still appears for "git stash <tab>"
+ when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still
+ complete options for
+
+ git stash save --<tab>
+
+ which is helpful for folks with finger-memory for save.
## contrib/completion/git-completion.bash ##
@@ contrib/completion/git-completion.bash: _git_stash ()
base-commit: 6de20f6092dcf9bdb1c8efe03db4b70c82b423dd
Signature · 1 line
2.56.0.237.g5414b88716.dirty
PATCH v2 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, bringing _git_stash closer in line with other completion helpers. As a nice side-benefit, this also adds "store" subcommand completion, which is missing from the explicit list of subcommands.
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). One might think we need to give "save" to __git_resolve_builtins' 3rd exclude argument to prevent it from showing up, but we don't: "save" is already marked PARSE_OPT_NOCOMPLETE.
†We don't complete the "save" subcommand unless at least "sa" has been typed, but we do complete its options if explicitly typed. With this change, we will complete "save" if GIT_COMPLETION_SHOW_ALL=1.
--- contrib/completion/git-completion.bash | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
contrib/completion/git-completion.bash +6 -2
@@ -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
Signature · 1 line
2.56.0.237.g5414b88716.dirty
PATCH v2 2/5 Completion: extract common stash listing code
In reply to D. Ben KnobleWith no change in behavior, prepare to adjust how stashes are completed by centralizing candidate generation.
--- contrib/completion/git-completion.bash | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
contrib/completion/git-completion.bash +7 -4
@@ -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
Signature · 1 line
2.56.0.237.g5414b88716.dirty
Re: [PATCH v2 2/5] Completion: extract common stash listing code
Quoted 8 lines · D. Ben Knoble
With no change in behavior, prepare to adjust how stashes are completed by centralizing candidate generation.
Signed-off-by D. Ben Knoble <[email protected]>--- contrib/completion/git-completion.bash | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
contrib/completion/git-completion.bash _git_stash () · line 3603
Quoted 10 lines
contrib/completion/git-completion.bash +2
-4@@ -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 - __gitcomp_nl "$(__git stash list \ - | sed -n -e 's/:.*//p')" + __git_complete_stashes
Nice to see two of these unsightly constructs go ;-)
PATCH v2 3/5 completion: fix Zsh handling of stash names
In reply to D. Ben KnobleWhen 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=0Because 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 thinks 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 from Bash in our code 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.
--- contrib/completion/git-completion.zsh | 5 +++++ 1 file changed, 5 insertions(+)
contrib/completion/git-completion.zsh +5 -0
@@ -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"
Signature · 1 line
2.56.0.237.g5414b88716.dirty
PATCH v2 4/5 doc: drop usage mentions of "git stash save"
In reply to D. Ben KnobleEven 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.
--- Documentation/git-stash.adoc | 2 -- builtin/stash.c | 1 - 2 files changed, 3 deletions(-)
Documentation/git-stash.adoc +0 -2
@@ -18,8 +18,6 @@ git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | - [-u | --include-untracked] [-a | --all] [(-m | --message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...] -git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet] - [-u | --include-untracked] [-a | --all] [<message>] git stash clear git stash create [<message>] git stash store [(-m | --message) <message>] [-q | --quiet] <commit>
builtin/stash.c +0 -1
@@ -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,
Signature · 1 line
2.56.0.237.g5414b88716.dirty
PATCH v2 5/5 completion: drop "stash save" completion altogether
In reply to D. Ben KnobleIt'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. It still appears for "git stash <tab>" when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still complete options for
git stash save --<tab>
which is helpful for folks with finger-memory for save.
--- contrib/completion/git-completion.bash | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
contrib/completion/git-completion.bash +1 -4
@@ -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" ;;
Signature · 1 line
2.56.0.237.g5414b88716.dirty
Re: [PATCH v2 5/5] completion: drop "stash save" completion altogether
Quoted 4 lines · D. Ben Knoble
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.
Quoted 8 lines
Since we recommend push instead, stop completing for "save" and remove a special case in completion code. It still appears for "git stash <tab>" when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still complete options for
git stash save --<tab>
which is helpful for folks with finger-memory for save.
Well, if we can replace the command line to "git stash push --" on the first <tab> and then start completing for "stash push" with the second <tab>, it would be superb.
Quoted 9 lines
contrib/completion/git-completion.bash +0
-1@@ -3558,16 +3558,13 @@ _git_stash () __git_resolve_builtins stash subcommands="$___git_resolved_builtins" - subcommand="$(__git_find_on_cmdline "$subcommands save")"
contrib/completion/git-completion.bash _git_stash () · line 3570
Quoted 10 lines
contrib/completion/git-completion.bash +1
-3+ 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" - ;;
Nice to see this go. This would have been maintenance nightmare if left forever as we will have to remember updating it when "sa" no longer becomes a unique prefix.
Re: [PATCH v2 5/5] completion: drop "stash save" completion altogether
Quoted 14 lines · Junio C Hamano
Quoted 9 lines · "D. Ben Knoble
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. It still appears for "git stash <tab>" when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still complete options for
Quoted 7 lines
Quoted 3 lines
git stash save --<tab>
which is helpful for folks with finger-memory for save.
Well, if we can replace the command line to "git stash push --" on the first <tab> and then start completing for "stash push" with the second <tab>, it would be superb.
We probably can (I know Zsh is capable), but that means more complex special-casing ;) I’d rather get rid of this case and leave that nicety for someone who’s motivated to get consensus for it, which I am not.
Quoted 24 lines
Quoted 10 lines
contrib/completion/git-completion.bash +0
-1@@ -3558,16 +3558,13 @@ _git_stash () __git_resolve_builtins stash subcommands="$___git_resolved_builtins" - subcommand="$(__git_find_on_cmdline "$subcommands save")"contrib/completion/git-completion.bash _git_stash () · line 3570
Quoted 10 lines
contrib/completion/git-completion.bash +1
-3+ 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" - ;;Nice to see this go. This would have been maintenance nightmare if left forever as we will have to remember updating it when "sa" no longer becomes a unique prefix.
Quoted 10 lines · D. Ben Knoble
This short patch series takes care of a few paper cuts in stash completion. The first patch is a small code cleanup I noticed a while back while working on
bfc1b34859(completion: add stash import, export, 2026-02-07), I think. The next 2 take care of a problem I've been having with Zsh's completion of stashes (cf. Unix & Linux SE [1]).[1]: https://unix.stackexchange.com/q/807580/301073
[snip]
Quoted 7 lines
Generated-with: git format-patch @{u}.. -o p -v2 --range-diff=@{u}..d1d0bf2d9a7d380d10771b5d1bceb8db91c5f05e [email protected] --cc='Patrick Steinhardt <[email protected]>'
I accidentally left the above line in v1, but I'm considering leaving it in from now on?
;)
Quoted 7 lines
It's the exact command I run to generate patches; I store it as a "trailer" in the branch description, then run "git generated-with"† which (effectively) does
eval "$(git bdesc | git interpret-trailers --parse | grep^Generated-with | cut -d: -f 2-)"
Quoted 7 lines
where "bdesc" is an alias for
git -c core.editor=cat branch --edit-description | git stripspace -sAnyway, I've been hand-editing them out of cover letters for the last few series, but if it doesn't bother anyone I'll just leave it around. Might be helpful for new folks learning how to format patches?
I think it’s a decent-to-good idea to leave it in.
Quoted 4 lines
†:
https://github.com/benknoble/Dotfiles/blob/master/links/bin/git-generated-with
[snip]
Quoted 4 lines · D. Ben Knoble
Diff-intervalle contre v1 :
1:d0e461a14a! 1:90d36b6445completion: simplify stash subcommand completion
@@ Commit message
The stash completion helper contains a hard-coded list of commands, but
Quoted 8 lines
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_stashcloser in line with
- other completion helpers.
+__git_resolve_builtins, so use it, bringing_git_stashcloser in line
+ with other completion helpers. As a nice side-benefit, this also adds
+ "store" subcommand completion, which is missing from the explicit list
+ of subcommands.
Yup.
Quoted 5 lines
- Note that we maintain the "save" special case, since it was removed from
+ Note that we maintain the "save" special case†, since it was removed from
default completion in0eb5a4f911(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
Quoted 8 lines
- save is already marked
PARSE_OPT_NOCOMPLETE.
+ stash by default, 2018-04-20). One might think we need to give "save" to
+__git_resolve_builtins' 3rd exclude argument to prevent it from
+ showing up, but we don't: "save" is already markedPARSE_OPT_NOCOMPLETE.
+
+ †We don't complete the "save" subcommand unless at least "sa" has been
+ typed, but we do complete its options if explicitly typed. With this
+ change, we will complete "save" if GIT_COMPLETION_SHOW_ALL=1.
Good.
Quoted 4 lines
5:
d1d0bf2d9a! 5:0266646fb4completion: drop "stash save" completion altogether
@@ Commit message
further documentation suggesting to use it.
Quoted 9 lines
Since we recommend push instead, stop completing for "save" and remove a
- special case in completion code.
+ special case in completion code. It still appears for "git stash <tab>"
+ when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still
+ complete options for
+
+ git stash save --<tab>
+
+ which is helpful for folks with finger-memory for save.
Agreed, documenting the status quo feels reasonable to me.
So overall I'm happy with this v2, thanks!
Patrick
Quoted 9 lines · Patrick Steinhardt
Quoted 8 lines
- special case in completion code. + special case in completion code. It still appears for "git stash <tab>" + when GIT_COMPLETION_SHOW_ALL=1, and when typed explicitly we still + complete options for+
+ git stash save --<tab>
+
+ which is helpful for folks with finger-memory for save.
Quoted 3 lines
Agreed, documenting the status quo feels reasonable to me.
So overall I'm happy with this v2, thanks!
Thanks for writing and reviewing.