zsh prompt: check whether inside git repository and not being ignored by git
git check-ignore .
will fail with exit code 128 if .
isn’t in a git
repository (or any other error occurs), and with exit code 1 only if the path isn’t ignored. So you can check for the latter only:
git check-ignore -q . 2>/dev/null; if [ "$?" -ne "1" ]; then ...
Inside the then
, you’re handling the case where .
is ignored or not in a git repository.
To make this work across file system boundaries, set GIT_DISCOVERY_ACROSS_FILESYSTEM
to true
:
GIT_DISCOVERY_ACROSS_FILESYSTEM=true git check-ignore -q . 2>/dev/null; if [ "$?" -ne "1" ]; then ...
First it should be:
if
git rev-parse --is-inside-work-tree >/dev/null 2>&1 &&
! git check-ignore . >/dev/null 2>&1
then...
Command substitution ($(...)
) is to retrieve the output of a command. Here, there's no output as you're redirecting it to /dev/null
and if there were, it would be taken as a command to execute (and check its exit status).
Note that the second command is only run if the first one succeeded.
@StephenKitt has shown how to factorize those two commands into one git
command, but if that still doesn't help wrt performance, you could always cache the information in an associative array.
typeset -A is_git # declared globally in your ~/.zshrc
if (( ! $+is_git[$PWD] )); then
git check-ignore -q . 2> /dev/null
is_git[$PWD]=$(( $? == 1 ))
fi
if (( $is_git[$PWD] )); then...
That cache could become stale if you rename directories, delete .git
directories, or change your list of ignored files. You can invalidate it with is_git=()
or by restarting zsh
with exec zsh
.
Another option would be to make that check only when you enter a directory using the chpwd
hook:
check_git() {
git check-ignore -q . 2> /dev/null
(( is_git = $? == 1 ))
}
chpwd_functions+=(check_git)
And then, in your prompt routine, it's just a matter of:
if (( is_git )); then...