gitautocompletezshtig

git completion in zsh: __git_func_wrap:3: : not found


git-completion.zsh and git-completion.bash are installed automatically when running brew install git:

❯ ls -l /usr/local/share/zsh/site-functions/_git
lrwxr-xr-x 56 quanta  7 Jul 18:54 /usr/local/share/zsh/site-functions/_git -> ../../../Cellar/git/2.27.0/share/zsh/site-functions/_git

❯ ls -l /usr/local/share/zsh/site-functions/git-completion.bash
lrwxr-xr-x 71 quanta  7 Jul 18:54 /usr/local/share/zsh/site-functions/git-completion.bash -> ../../../Cellar/git/2.27.0/share/zsh/site-functions/git-completion.bash

/usr/local/share/zsh/site-functions is included in fpath:

❯ echo $fpath
/usr/local/share/zsh-completions
/usr/local/share/zsh/site-functions
/usr/share/zsh/site-functions
/usr/share/zsh/5.7.1/functions

For some reasons, sometimes when I type git reba and press tab:

❯ git reba
__git_func_wrap:3: : not found
__git_func_wrap:3: : not found    

❯ type __git_func_wrap
__git_func_wrap is a shell function from /usr/local/share/zsh/site-functions/git-completion.bash

https://github.com/git/git/blob/master/contrib/completion/git-completion.bash#L3517-L3522

❯ grep -A5 '^__git_func_wrap' /usr/local/share/zsh/site-functions/git-completion.bash
__git_func_wrap ()
{
    local cur words cword prev
    _get_comp_words_by_ref -n =: cur words cword prev
    $1
}

What the default completion is:

❯ complete -p git
complete -o bashdefault -o default -o nospace -F __git_wrap_tig tig
complete _bash bash

Continue inspect:

❯ type __git_wrap_tig
__git_wrap_tig is a shell function from /usr/local/share/zsh/site-functions/tig-completion.bash

The thing is I cannot find this function in tig-completion.bash

tig: stable 2.5.1 (bottled), HEAD
Text interface for Git repositories
https://jonas.github.io/tig/
/usr/local/Cellar/tig/2.5.1 (15 files, 875.9KB) *
  Poured from bottle on 2020-07-06 at 16:01:38
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/tig.rb
==> Dependencies
Required: readline ✔
==> Options
--HEAD
    Install HEAD version
==> Caveats
A sample of the default configuration has been installed to:
  /usr/local/opt/tig/share/tig/examples/tigrc
to override the system-wide default configuration, copy the sample to:
  /usr/local/etc/tigrc

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions and functions have been installed to:
  /usr/local/share/zsh/site-functions

Looks like there is some changed recently: https://github.com/jonas/tig/commit/26ab51d28133354bfaa94d064bff37d29b3c30e3

but where is __git_wrap_tig function?

PS: As I said above, this problem is not happen every time. Sometimes, when I opened a new tab and check the default completion and it is just:

❯ complete -p git
complete _bash bash

and git completion worked as expected.


Reply to @user1934428:

❯ grep '__git_complete ' /usr/local/share/zsh/site-functions/git-completion.bash
__git_complete ()
__git_complete git __git_main
__git_complete gitk __gitk_main
__git_complete git.exe __git_main

and one more invocation of __git_complete is in tig-completion.bash:

# we use internal git-completion functions, so wrap _tig for all necessary
# variables (like cword and prev) to be defined
__git_complete tig _tig 

Solution

  • TL;DR

    This is a problem with the tig completion definitions, and not with the git completion definitions.

    Activating completion on tig breaks completion for git.

    Mitigation:

    Install the old versions of the completion scripts.

    Unlink _tig and tig-completion.bash in /usr/local/share/zsh/site-functions and replace with these older versions. Rename tig-completion.zsh as _tig when downloading.

    cd /usr/local/share/zsh/site-functions && \
    rm -f _tig tig-completion.bash && \
    wget -O _tig https://raw.githubusercontent.com/jonas/tig/91912eb97da4f6907015dab41ef9bba315730854/contrib/tig-completion.zsh && \
    wget -O tig-completion.bash https://raw.githubusercontent.com/jonas/tig/c72aa4dab21077231a97dcca8e3821d7b35fe7db/contrib/tig-completion.bash
    

    Solution:

    TODO: File issue with tig. This is a regression with the new completion script as implemented in jonas/tig#960

    States:

    I start with git tab completion working, and then at some point the shell "goes bad." I actually have three states

    1. initial state. working. complete not defined.
      % which complete
      
    2. still working after a first tab completion which creates a definition for complete
      % git <TAB>
      add       -- add file contents to the index
      bisect    -- find by binary search the change that introduced a bug
      ...
      % which complete
      complete () {
              return 0
      }
      
    3. not working. complete function defined referencing bash
          complete () {
              emulate -L zsh
              local args void cmd print remove
              args=("$@")
              zparseopts -D -a void o: A: G: W: C: F: P: S: X: a b c d e f g j k u v p=print r=remove
              if [[ -n $print ]]
              then
                      printf 'complete %2$s %1$s\n' "${(@kv)_comps[(R)_bash*]#* }"
              elif [[ -n $remove ]]
              then
                  for cmd
                  do
                          unset "_comps[$cmd]"
                  done
              else
                      compdef _bash_complete\ ${(j. .)${(q)args[1,-1-$#]}} "$@"
              fi
          }
      

    Research

    complete() function:

    unsetting the complete function unset -f complete does not magically fix it. I think this may leave me with no completion for git?

    virtual envs

    I jump in and out of virtual envs, and thought that was related, but a controlled example of jumping in and out and manually setting VIRTUAL_ENV and etc did not bleed over and affect the completion system.

    distraction, not related

    local variables

    Digging further I found a lot of local variables set in the third case, "bad shell."

    I removed each of these local variables without any positive effect:

    % unset REPLY
    % unset __git_repo_path
    % unset __tig_commands
    % unset __tig_options
    % unset _ack_raw_types
    % unset $_cmd_variant
    % unset _cmd_variant
    

    tig

    Progress! I can move from state 1 to state 2 by invoking completion on tig:

    % git <TAB>
    add       -- add file contents to the index
    bisect    -- find by binary search the change that introduced a bug
    ...
    % tig <TAB>
    % git <TAB>
    __git_func_wrap:3: : not found
    

    related broken state by completing with tig first:

    % tig <TAB>
    __git_complete:5: command not found: complete
    % which complete
    complete () {
            emulate -L zsh
            local args void cmd print remove
            args=("$@")
            zparseopts -D -a void o: A: G: W: C: F: P: S: X: a b c d e f g j k u v p=print r=remove
            if [[ -n $print ]]
            then
                    printf 'complete %2$s %1$s\n' "${(@kv)_comps[(R)_bash*]#* }"
            elif [[ -n $remove ]]
            then
                    for cmd
                    do
                            unset "_comps[$cmd]"
                    done
            else
                    compdef _bash_complete\ ${(j. .)${(q)args[1,-1-$#]}} "$@"
            fi
    }
    % git <TAB>
    __git_func_wrap:3: : not found
    

    fpath and tig completion

    % echo $fpath
    /usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/5.7.1/functions
    
    % for f in $fpath; do ls $f/*tig*; done | cat
    /usr/local/share/zsh/site-functions/_tig
    /usr/local/share/zsh/site-functions/tig-completion.bash
    zsh: no matches found: /usr/share/zsh/site-functions/*tig*
    zsh: no matches found: /usr/share/zsh/5.7.1/functions/*tig*
    
    

    Brew sources for site-functions for git, tig

    % cd /usr/local/share/zsh/site-functions
    % ls -l *tig*
    _tig -> ../../../Cellar/tig/2.5.1/share/zsh/site-functions/_tig
    tig-completion.bash -> ../../../Cellar/tig/2.5.1/share/zsh/site-functions/tig-completion.bash
    % ls -l *git*
    _git -> ../../../Cellar/git/2.28.0/share/zsh/site-functions/_git
    git-completion.bash -> ../../../Cellar/git/2.28.0/share/zsh/site-functions/git-completion.bash
    

    Tig completions in /usr/local/share/zsh/site-functions