I'm trying to set up a zsh function that will take me back to the top level git directory with an optional argument to move relative to that directory. I've currently got this which works:

alias gitdir='git rev-parse --show-toplevel'
cdgit() { cd $(gitdir)/$1 }

The issue is, tab completion doesn't work properly, it will autocomplete from whatever directory I'm in when I run cdgit, but I want it to complete from $(gitdir). If I type the following line before running cdgit, the completion will work correctly (from $(gitdir)):

compctl -W $(gitdir) -/ cdgit

However, I don't want to type that command every time before I type cdgit just to get tab completion. Is there any way that I can make a completion function for cdgit that will somehow run that command so my completion is correct?

  • Why the downvote? Jun 13, 2016 at 14:42
  • Why don't you want to stick with the compctl solution? This can go to the rc file where you define the cdgit function, can't it?!
    – mpy
    Jun 14, 2016 at 18:58
  • 1
    No, because I don't want it to run when my shell starts. That would change the directory that cdgit <path> completes to to whatever $(gitdir) evaluated to at the time that my .zshrc was run. However, I want it to autocomplete to whatever $(gitdir) evaluates to at the time that I type cdgit <path>. So I want to type cdgit and press tab and get completion from where it would cd me to, which might not be the same place as when the shell was started. Jun 14, 2016 at 20:00
  • It could potentially run on every directory change, I guess. Not the cleanest solution but it's a quick command. Jun 14, 2016 at 20:01
  • Of course, my bad not realizing that $(gitdir) will be static then. See my answer for a suggestion.
    – mpy
    Jun 15, 2016 at 16:46

1 Answer 1


I'd suggest to write a completion function for your cdgit function.

Put this file named _cdgit into a directory which is in your $fpath, e.g. /usr/share/zsh/site-functions, then start a new shell instance:

#compdef cdgit

local expl
local ret=1

[[ CURRENT -eq 2 ]] && _wanted directories expl 'git toplevel directory' \
    _path_files -/ -W $(git rev-parse --show-toplevel) && ret=0

return ret

This is borrowed from one of the last lines in the _cd completion function itself, which is of course much more complex.


/usr/src/linux-git/Documentation/x86> cd [TAB]
local directory
i386/    x86_64/

/usr/src/linux-git/Documentation/x86> cdgit [TAB]
git toplevel directory
Documentation/  crypto/         include/        lib/            scripts/        usr/                          
arch/           drivers/        init/           mm/             security/       virt/                         
block/          firmware/       ipc/            net/            sound/                                      
certs/          fs/             kernel/         samples/        tools/                                      

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.