3

If I type git switch --no-guess <TAB><TAB> I am presented with a list of local branches as possible completions. If I don't pass --no-guess then both local and remote branches are presented.

I created a git alias sb = switch --no-guess, but when I type: git sb <TAB><TAB> I am given both local and remote branches (i.e. it works as a completion as if I did not use --no-guess).

Is there a way to fix this?

Zorzella
  • 8,661
  • 3
  • 19
  • 13
  • 1
    Does this answer your question? [How do I get bash completion to work with aliases?](https://stackoverflow.com/questions/342969/how-do-i-get-bash-completion-to-work-with-aliases) – tjm3772 Apr 11 '23 at 19:17
  • No, this is also about a bash alias to a git command. – Zorzella Apr 14 '23 at 19:56

1 Answers1

2

The completion script distributed with git does not have this capability built in, so here’s a crude patch to add it. Written against git 2.39.2 and tested only in bash 5.2.15.

--- /usr/share/bash-completion/completions/git
+++ /usr/share/bash-completion/completions/git
@@ -1131,23 +1131,34 @@
    __git_get_config_variables "pretty"
 }
 
-# __git_aliased_command requires 1 argument
 __git_aliased_command ()
 {
-   local cur=$1 last list= word cmdline
+   local -n cmdvar=$1
+   local -n argsvar=$2
+   local -n idxvar=$3
+
+   local found=
+   local -a stack=()
+
+   local cur="${cmdvar}"
+   local cur_idx=0
+   argsvar=("$cur")
 
    while [[ -n "$cur" ]]; do
-       if [[ "$list" == *" $cur "* ]]; then
-           # loop detected
-           return
+       if ! expanded=$(__git config --get "alias.$cur") ; then
+           break
        fi
 
-       cmdline=$(__git config --get "alias.$cur")
-       list=" $cur $list"
-       last=$cur
-       cur=
+       if [[ "$stack" == *" $cur "* ]]; then
+           # loop detected
+           return 1
+       fi
+       stack+=("$cur")
 
-       for word in $cmdline; do
+       found=1
+       argsvar=("${argsvar[@]:0:cur_idx}" $expanded "${argsvar[@]:cur_idx+1}")
+
+       for word in "${argsvar[@]:cur_idx}"; do
            case "$word" in
            \!gitk|gitk)
                cur="gitk"
@@ -1165,13 +1177,16 @@
                cur="$word"
                break
            esac
+           (( cur_idx++ ))
        done
    done
 
-   cur=$last
-   if [[ "$cur" != "$1" ]]; then
-       echo "$cur"
+   if [[ -n "$found" ]]; then
+       cmdvar="$cur"
+       idxvar="$cur_idx"
+       return 0
    fi
+   return 1
 }
 
 # Check whether one of the given words is present on the command line,
@@ -3507,10 +3522,13 @@
 
    __git_complete_command "$command" && return
 
-   local expansion=$(__git_aliased_command "$command")
-   if [ -n "$expansion" ]; then
-       words[1]=$expansion
-       __git_complete_command "$expansion"
+   local expansion_cmd_idx
+   local -a expansion
+   if __git_aliased_command command expansion expansion_cmd_idx; then
+       words=("${words[@]:0:__git_cmd_idx}" "${expansion[@]}" "${words[@]:__git_cmd_idx+1}")
+       (( cword += "${#expansion[@]}" - 1 ))
+       (( __git_cmd_idx += expansion_cmd_idx ))
+       __git_complete_command "$command"
    fi
 }
 

This corresponds to the file contrib/completion/git-completion.bash in the git source distribution (possibly offset). Check with your OS distribution to find out where it installs that file if you want to apply this as a monkey patch; the above can be applied directly it using patch -Np0 on Debian-based distributions.

user3840170
  • 26,597
  • 4
  • 30
  • 62