Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git completion fails when complete_aliases option is set #2394

Closed
slhck opened this issue Jan 2, 2014 · 40 comments
Closed

git completion fails when complete_aliases option is set #2394

slhck opened this issue Jan 2, 2014 · 40 comments

Comments

@slhck
Copy link

slhck commented Jan 2, 2014

I'm running zsh 5.0.4 on OS X 10.8 with oh-my-zsh a38af27 with the git plugin. When I type gco <TAB>, I get the following output:

% gco zsh:12: command not found: __git-checkout_main
extegco
file
MIT-LICENSE.txt  custom/          log/             plugins/         themes/
README.textile   lib/             oh-my-zsh.sh     templates/       tools/

I've found the culprit to be the option complete_aliases. Once I turn it off, everything works as expected.

What gives? Is there any option clash? I haven't changed my .zshrc in ages, and I've always had complete_aliases on.

I don't particularly need this option but I guess there's some bug here.

@mecampbellsoup
Copy link

👍 Same issue exactly... very puzzling.

@ncanceill
Copy link
Contributor

Interesting.

For the lazy, here is what the Zsh guide has to say about complete_aliases:

Prevents aliases on the command line from being internally substituted before completion is attempted. The effect is to make the alias a distinct command for completion purposes.

However, since 57f55e6 and 2e94929, the aliases from the git plugin have their own completion set, and redirected to the proper git subcommand, including gco. So this issue should not be happening. Does anyone has any idea why it still is?

Finally, I am not able to reproduce the issue with Zsh 5.0.2 on Mac 10.9.2: complete_aliases does not change the behavior of completion on gco at all, even if I clear the completion cache.

@slhck @mecampbellsoup can you try with the template .zshrc and see if it is still happening?

Also @mecampbellsoup can you post your system config and Zsh version?

@mcornella @simonweil (my happy helpers =D) can you try to reproduce the issue?

@slhck
Copy link
Author

slhck commented Apr 22, 2014

I'm now on Zsh 5.0.5 with oh-my-zsh eafd5f3. If I use the template .zshrc there is no problem. Of course, because there is no complete_aliases option in there.

As soon as I include setopt complete_aliases, pressing Tab after gco gets me the same old error.

@mecampbellsoup
Copy link

@ncanceill Sure, here you go:

⇒  zsh --version
zsh 5.0.5 (x86_64-apple-darwin13.0.0)⇒  zsh --version
zsh 5.0.5 (x86_64-apple-darwin13.0.0)

My full .zshrc and zsh configs can be found here: https://github.com/mecampbellsoup/dotfiles/tree/master/zsh

oh-my-zsh version is eafd5f3 as well.

@mcornella
Copy link
Member

No idea.. maybe compinit cache fault? If so, try deleting the files .zcompdump* in your $HOME directory

@slhck
Copy link
Author

slhck commented Apr 22, 2014

@mcornella That didn't help, unfortunately.

@mecampbellsoup
Copy link

@slhck I think perhaps we should start checking out previous zsh commits to see if we can locate the bug...?

@ncanceill
Copy link
Contributor

@mecampbellsoup yes, that could be helpful! I recommend the use of git-bisect.


The non-reproducibility of the issue suggests that it has something to do with your config, and the fact that it still happens with the template .zshrc indicates that it is not related to your OMZ config.

Let us start with determining what the compdef statement should do. Reading through Zsh completion manual indicates a bit more about how it should work:

#compdef names... [ -[pP] patterns... [ -N names... ] ]
Each name may also be of the form ‘cmd=service’. When completing the command cmd, the function typically behaves as if the command (or special context) service was being completed instead. This provides a way of altering the behaviour of functions that can perform many different completions. It is implemented by setting the parameter $service when calling the function; the function may choose to interpret this how it wishes, and simpler functions will probably ignore it.

compdef [ -ane ] function names... [ -[pP] patterns... [ -N names... ] ]
The first form defines the function to call for completion in the given contexts as described for the #compdef tag above.
Alternatively, all the arguments may have the form ‘cmd=service’. Here service should already have been defined by ‘cmd1=service’ lines in #compdef files, as described above. The argument for cmd will be completed in the same way as service.

But then I had a look at the Zsh git completion (with the oh-so-evil 6661 line count), and git-checkout is not listed in the #compdef statement, and $service is not checked for it either. So I have no clue as to why compdef _git gco=git-checkout works — but it does work!

@pielgrzym can you enlighten us about 2e94929?

@mcornella
Copy link
Member

Nice digging @ncanceill!

$service is not checked for it either. So I have no clue as to why compdef _git gco=git-checkout works — but it does work!

It is indeed checked for inside the _git() function, CTRL+F shows that it's a simple if-else:

if [[ $service == git ]]; then
    [...]
else
    _call_function ret _$service
fi

so it then calls _git-checkout, which is also defined, but only if it's not previously defined:

(( $+functions[_git-checkout] )) ||
_git-checkout () { [...] }

Maybe they both have a custom _git-checkout function defined somewhere else that triggers this behaviour?
Also, the error message spits out __git-checkout_main (with two underscores), and then extegco\n file. It seems to me that the message is overwritten, as if zle had something to do with that..

BTW, the source you linked was from the master branch, here are both 5.0.4 and 5.0.5

@ncanceill
Copy link
Contributor

Thanks @mcornella, I found the check for $service == git but stupidly disregarded the else clause! And I did not find the courage to play with SF's git viewer (which BTW does not have line numbers!) to look for a specific point in history, lazy me!

I like your hint about _git-checkout not being defined because it is elsewhere. @slhck @mecampbellsoup can you run which _git-checkout to check that you have the proper function?

Concerning the weird output, I have seen zle do much weird stuff, so I am not too surprised. But I am as baffled by the __git-checkout_main as you are.

@mcornella
Copy link
Member

One last thing, using git checkout instead of gco should show the same behaviour

@mecampbellsoup
Copy link

@ncanceill @mcornella So here's some some output for you, both are taken after attempting tab completion:

matthewcampbell@Matthews-MacBook-Air:~/Sites/code/stack-builders/seo_platform|69220108_adjust_keyword_editing_on_dealer⚡
⇒  gco ......zsh:12: command not found: __git-checkout_main
⇒  git checkout
67061970_notify_sidekiq_hangs                            origin/67061970_notify_sidekiq_hangs                     production
67394702_track_keywords_change                           origin/67394702_track_keywords_change                    production_2014-04-21

(P.S. This is the same as the output when I just have alias gco=git checkout active and am using gco, i.e. after I comment out setopt complete_aliases in my .zshrc file)

And when I ask about which _git-checkout (and which __git-checkout as well):

⇒  which _git-checkout
_git-checkout not found
⇒  which __git-checkout
__git-checkout not found

@mcornella
Copy link
Member

Try this:

autoload -Uz _git-checkout && _git-checkout
which _git-checkout

Sorry, but it didn't become clear if the issue appeared using just git checkout <TAB> instead of gco <TAB>..

Also, try disabling OMZ entirely: that is, using a blank .zshrc file. Git completion should persist and the issue too

And one last thing, does the same thing happen in another git repository?

@mecampbellsoup
Copy link

@mcornella More output for ya':

⇒  autoload -Uz _git-checkout && _git-checkout
zsh: _git-checkout: function definition file not found
⇒  which _git-checkout
_git-checkout () {
    # undefined
    builtin autoload -XUz
}

It appears that basically all of my Git completion functions are broken, by the way (I have to <TAB> twice to make the errors appear):

⇒  ga ......zsh:12: command not found: __git-add_main
⇒  gco ......zsh:12: command not found: __git-checkout_main
⇒  gd ......zsh:12: command not found: __git-diff_main
⇒  gst ......zsh:12: command not found: __git-status_main

I'm at quite the loss. Let me know what else I can do to help.

@mecampbellsoup
Copy link

@mcornella Another super weird thing going on in my setup is the results of my where function:

⇒  where ruby
ruby: aliased to bundled_ruby
/Users/matthewcampbell/.rbenv/shims/ruby
/Users/matthewcampbell/.rbenv/shims/ruby
/usr/bin/ruby
⇒  where coqc
/usr/local/bin/coqc
/usr/local/bin/coqc
/usr/local/bin/coqc
/usr/local/bin/coqc

Why would ZSH be returning me the same result 4 times?!

@mcornella
Copy link
Member

Ok, bear with me, one last time:

autoload -Uz _git && _git
which _git-checkout

and

echo '$fpath = ('$fpath')'
echo '$path = ('$path')'

Also, try what I mentioned about using an empty .zshrc file

@mecampbellsoup
Copy link

⇒  autoload -Uz _git && _git
zsh:12: command not found: ___main
_default:compcall:12: can only be called from completion function
⇒  which _git-checkout
_git-checkout not found
echo '$fpath = ('$fpath')'
$fpath = (/Users/matthewcampbell/.oh-my-zsh/plugins/gem /Users/matthewcampbell/.oh-my-zsh/plugins/brew /Users/matthewcampbell/.oh-my-zsh/plugins/bundler /Users/matthewcampbell/.oh-my-zsh/plugins/git /Users/matthewcampbell/.oh-my-zsh/functions /Users/matthewcampbell/.oh-my-zsh/completions /Users/matthewcampbell/.dotfiles/zsh /Users/matthewcampbell/.dotfiles/xcode /Users/matthewcampbell/.dotfiles/vim /Users/matthewcampbell/.dotfiles/tmux /Users/matthewcampbell/.dotfiles/system /Users/matthewcampbell/.dotfiles/sublime2 /Users/matthewcampbell/.dotfiles/script /Users/matthewcampbell/.dotfiles/ruby /Users/matthewcampbell/.dotfiles/python /Users/matthewcampbell/.dotfiles/osx /Users/matthewcampbell/.dotfiles/macvim /Users/matthewcampbell/.dotfiles/homebrew /Users/matthewcampbell/.dotfiles/git /Users/matthewcampbell/.dotfiles/functions /Users/matthewcampbell/.dotfiles/ctags /Users/matthewcampbell/.dotfiles/cloudapp /Users/matthewcampbell/.dotfiles/bin /Users/matthewcampbell/.dotfiles/functions /usr/local/share/zsh/site-functions /usr/local/Cellar/zsh/5.0.5/share/zsh/functions)
echo '$path = ('$path')'
$path = (/Users/matthewcampbell/.rbenv/shims /usr/local/opt/coreutils/libexec/gnubin /usr/local/bin /Users/matthewcampbell/.cabal/bin /Applications/Postgres93.app/Contents/MacOS/bin /usr/local/bin /usr/local/heroku/bin ./bin /Users/matthewcampbell/.rbenv/shims /usr/local/bin /usr/local/sbin /Users/matthewcampbell/.sfs /Users/matthewcampbell/.dotfiles/bin /usr/bin /bin /usr/sbin /sbin /usr/local/bin /opt/X11/bin /usr/local/go/bin /usr/local/MacGPG2/bin /Users/matthewcampbell/.rbenv/shims /usr/local/opt/coreutils/libexec/gnubin /Users/matthewcampbell/.cabal/bin /Applications/Postgres93.app/Contents/MacOS/bin /usr/local/heroku/bin ./bin /usr/local/sbin /Users/matthewcampbell/.sfs /Users/matthewcampbell/.dotfiles/bin /usr/local/Cellar/go/1.2.1/bin /usr/local/Cellar/go/1.2.1/bin)

Also, try disabling OMZ entirely: that is, using a blank .zshrc file. Git completion should persist and the issue too

Matthews-MacBook-Air% autoload -Uz _git-checkout && _git-checkout
zsh: _git-checkout: function definition file not found
Matthews-MacBook-Air% gd
zsh: command not found: gd
Matthews-MacBook-Air% gst
zsh: command not found: gst
Matthews-MacBook-Air% gco
zsh: command not found: gco

Looks like completion is not persisting...

@mcornella
Copy link
Member

⇒ autoload -Uz _git && _git
zsh:12: command not found: ___main

This confirms the issue happens with every git completion, I guess there's something wrong with _git(). Please post the result of which _git

Looks like completion is not persisting...

When you use zsh without oh-my-zsh, don't use the aliases but the full git command, since aliases are not defined without oh-my-zsh. You can navigate to a git repository and input any git command (e.g. git checkout <TAB>), with and without setopt completealiases; git completion is enabled by default.

Also, it appears you have duplicate entries in your $path; to enforce unique values add the command typeset -U path at the end of your .zshrc (after all path entries are added)

@mecampbellsoup
Copy link

Thanks @mcornella, very helpful for me.

⇒  which _git
_git () {
        local _ret=1
        local cur cword prev
        cur=${words[CURRENT]}
        prev=${words[CURRENT-1]}
        let cword=CURRENT-1
        if (( $+functions[__${service}_zsh_main] ))
        then
                __${service}_zsh_main
        else
                emulate ksh -c __${service}_main
        fi
        let _ret && _default && _ret=0
        return _ret
}

When you use zsh without oh-my-zsh, don't use the aliases but the full git command, since aliases are not defined without oh-my-zsh.

When I use the full git commands WITH ACTIVE OMZ, the behavior is a little different from what I used to have with the aliases... take a look:

⇒  git checkout <TAB>
64879538_fix_li_elements                             master                                               origin/master
64908958_center_products_text_in_div                 next_ror_post                                        origin/next_ror_post
64916916_fix_contact_emails                          origin/64879538_fix_li_elements                      origin/oss_contrib_blog_post
64919128_override_fonts                              origin/64908958_center_products_text_in_div          origin/production
65271680_fix_map_resizing                            origin/64916916_fix_contact_emails                   origin/sprites
65753620_translate_navigation_bar                    origin/64919128_override_fonts                       origin/title-update-final

In the past, when using gco <TAB> only the local branches would appear as options. In the above output, all branches on origin remote appear.

Here's output when I've disabled OMZ and run the same git commands:

Matthews-MacBook-Air% git checkout README.md
Procfile                 Setup.hs                 circle.yml               dist/                    node_modules/            stackbuilders.com.cabal
README.md                assets/                  client_session_key.aes   news/                    src/                     tests/

It seems to be, well, broken, which makes sense since I've disabled the git plugin as that's enabled in my .zshrc.

@mcornella
Copy link
Member

Ok, now we know where do these _git-checkout_main come from. Your _git() function is messed up, but I don't know why. I assume you have setopt completealiases in your .zshrc. Go ahead and disable that, and then run which _git again.
Also, post the file /usr/local/Cellar/zsh/5.0.5/share/zsh/functions/Completion/Unix/_git on a gist

@mecampbellsoup
Copy link

This is with setopt complete_aliases disabled:

⇒  which _git
_git () {
    # undefined
    builtin autoload -XUz
}

I don't seem to have that filepath - I have up to /functions but not /Completion and beyond... (lots omitted in what follows):

matthewcampbell@Matthews-MacBook-Air:~|
⇒  vim /usr/local/Cellar/zsh/5.0.5/share/zsh/functions/
VCS_INFO_adjust                _dmidecode                     _matlab                        _snoop                         _zpty
VCS_INFO_bydir_detect          _domains                       _md5sum                        _socket                        _zsh-mime-handler
VCS_INFO_check_com             _dpatch-edit-patch             _mdadm                         _sockstat                      _zstyle
VCS_INFO_detect_bzr            _dpkg                          _members                       _softwareupdate                _ztodo
VCS_INFO_detect_cdv            _dpkg-buildpackage             _mencal                        _sort                          _zypper

@mcornella
Copy link
Member

Ok, the filepath must be /usr/local/Cellar/zsh/5.0.5/functions/Completion/Unix/_git

Regarding _git(), you need to try to autocomplete some git command before running which _git

@mecampbellsoup
Copy link

Still can't locate that filepath brother... here's a Gist with the output of tree running from within my ZSH directory: https://gist.github.com/mecampbellsoup/1065d4228b143140ac69

Here's which _git after running an autocompleted function (specifically I tried ga, gd, and gc):

⇒  which _git
_git () {
    local _ret=1
    local cur cword prev
    cur=${words[CURRENT]}
    prev=${words[CURRENT-1]}
    let cword=CURRENT-1
    if (( $+functions[__${service}_zsh_main] ))
    then
        __${service}_zsh_main
    else
        emulate ksh -c __${service}_main
    fi
    let _ret && _default && _ret=0
    return _ret
}

@mcornella
Copy link
Member

Ok, I understand now how Homebrew installs zsh, thanks for that tree gist! Your _git completion file is therefore in /usr/local/Cellar/zsh/5.0.5/functions/_git. Please post that.

I'm beginning to think this is an issue with your homebrew installation of zsh. Maybe you should uninstall it and reinstall it again.. Or ask the @Homebrew guys?

@mecampbellsoup
Copy link

https://gist.github.com/80a00d7af3766c1ad6dc

@mcornella Do you think it could have something to do with the dotfiles I installed not too long ago? They're @holman's... https://github.com/mecampbellsoup/dotfiles/blob/master/zsh/config.zsh

@mcornella
Copy link
Member

Well, you're installation of zsh is correct. It seems though you have some other place that's redefining your git completion, because your which _git and the function _git() defined in the _git file provided in the gist are very different.

Do you think it could have something to do with the dotfiles I installed not too long ago?

That may be it yes. In this file it's sourcing a completion file, check that one out for me, please and thank you: cat $(brew --prefix)/share/zsh/site-functions/_git

@slhck, may that be the same issue, do you have @holman's dotfiles as well?

@mecampbellsoup
Copy link

@mcornella
Copy link
Member

Yes, that file is the culprit. The definition of the _git () function is at the bottom of the file, you'll see that it matches the output of which _git you're getting.

I don't know how you should proceed now. You could rename the file you just gisted so that your dotfiles won't find it, or delete your dotfiles entirely, or just remove the dotfiles/git/completion.zsh from your fork (but then you'll have merge conflicts from updating dotfiles).

@mecampbellsoup
Copy link

@mcornella Sorry, how do you explain this behavior exactly? I'm a bit confused :/

⇒  which _git
_git () {
    # undefined
    builtin autoload -XUz
}
matthewcampbell@Matthews-MacBook-Air:~/.dotfiles|master⚡
⇒  ga
Nothing specified, nothing added.
Maybe you wanted to say 'git add .'?
matthewcampbell@Matthews-MacBook-Air:~/.dotfiles|master⚡
⇒  which _git
_git () {
    local _ret=1
    local cur cword prev
    cur=${words[CURRENT]}
    prev=${words[CURRENT-1]}
    let cword=CURRENT-1
    if (( $+functions[__${service}_zsh_main] ))
    then
        __${service}_zsh_main
    else
        emulate ksh -c __${service}_main
    fi
    let _ret && _default && _ret=0
    return _ret
}

@mcornella
Copy link
Member

For this behaviour you mean the different output of both which _git? If so, that's because the completion is autoloaded, as you see in the first which _git. This means that the definition is only loaded when first needed, so the first time you ask for the completion of a git command, that's when the _git function loads the definition.

@mecampbellsoup
Copy link

And the correct behavior is likely being overwritten at some point, probably by something in my config.zsh?

@mcornella
Copy link
Member

Yes, the file that loads the older completion is this file in your dotfiles. If you delete it you'll have the proper completion back.

@mcornella
Copy link
Member

This looks a lot like you did brew install hub. Take a look at this comment and this issue: #1727.
Following the advice on the last one will fix this.

@mcornella
Copy link
Member

@slhck you will find your fix in this comment: #2800 (comment)

@slhck
Copy link
Author

slhck commented May 31, 2014

@mcornella Sorry for the late reply. I did not have access to the machine that exposed the problem.

Running

brew uninstall --force git && brew install git --without-completions

solved the problem indeed.

Thank you very much for your investigation.

@felipec
Copy link
Contributor

felipec commented Jun 5, 2014

The problem here is that the official Git completion was not prepared for 'complete_aliases', I've pushed a fix:

felipec/git@aaafa76

This way you can manually define the completion with:

compdef _git gco=git_checkout

However, if you want to use zsh's format: gco=git-checkout and for it to work in the currently distributed version of Git, you can do this:

alias __git-checkout_main=_git_checkout

@flyinhigh
Copy link

find .zshrc and remove comment

Example aliases

alias zshconfig="st ~/.zshrc"
#####here####

alias ohmyzsh="mate ~/.oh-my-zsh"

alias gco="git checkout"

cbliard pushed a commit to cbliard/dotfiles that referenced this issue Jun 18, 2015
derekprior added a commit to derekprior/dotfiles that referenced this issue Sep 24, 2015
gabebw added a commit to gabebw/dotfiles that referenced this issue Nov 3, 2017
ohmyzsh/ohmyzsh#2394 (comment)

Unfortunately, it doesn't complete remote branches.
@jessrosenfield
Copy link

jessrosenfield commented May 4, 2020

Can anyone help me debug why I'm getting this issue? It happens with and without complete_aliases set. Also, removing .zcompdump* files doesn't fix it. My plugins are just set to plugins=(git gitfast), however I get these issues with function completions (which is frustrating because I'd ideally use my own customized gco function instead of the git plugin's gco alias).
ggl _git:12: command not found: __git-checkout_main
gdv _git:12: command not found: __git-diff_main

I'm using Powerlevel10k on oh-my-zsh 173d4ca, with zsh 5.8 (x86_64-apple-darwin19.3.0) and git version 2.26.1. Unfortunately brew uninstall --force git && brew install git --without-completions is no longer an option with git.

Here is my definition of _git.

❯ which _git
_git () {
	local _ret=1
	local cur cword prev
	cur=${words[CURRENT]}
	prev=${words[CURRENT-1]}
	let cword=CURRENT-1
	if (( $+functions[__${service}_zsh_main] ))
	then
		__${service}_zsh_main
	else
		emulate ksh -c __${service}_main
	fi
	let _ret && _default && _ret=0
	return _ret
}

@felipec
Copy link
Contributor

felipec commented May 29, 2020

@jessrosenfield It's because you are missing a patch. I'm not sure if you are using the latest ohmyzsh, but there was some mismatch and my patch got reverted:

completion: zsh: improve main function selection

@jessrosenfield
Copy link

@felipec I updated but things still aren't working (my current issue #9018 is slightly different though)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants