Zsh prompt with asynchronous Git status
Vincent Bernat
Zsh ships vcs_info, a function fetching information about the
VCS state for the current directory and populating a variable that can
be used in a shell prompt. It supports several VCS, including Git and
SVN. Here is an example of configuration:
autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git
() {
local formats="${PRCH[branch]} %b%c%u"
local actionformats="${formats}%{${fg[default]}%} ${PRCH[sep]} %{${fg[green]}%}%a"
zstyle ':vcs_info:*:*' formats $formats
zstyle ':vcs_info:*:*' actionformats $actionformats
zstyle ':vcs_info:*:*' stagedstr "%{${fg[green]}%}${PRCH[circle]}"
zstyle ':vcs_info:*:*' unstagedstr "%{${fg[yellow]}%}${PRCH[circle]}"
zstyle ':vcs_info:*:*' check-for-changes true
}
add-zsh-hook precmd vcs_info
You can use ${vcs_info_msg_0_} in your prompt to display the current
branch, the presence of staged and unstaged changes, as well as the
ongoing action.1 Have a look at the documentation for more
details.

vcs_info function.On large repositories, some information is expensive to fetch. While
vcs_info queries Git, interactions with Zsh are stuck. A possible
solution is to execute vcs_info asynchronously with zsh-async.
The first step is to define a wrapper around vcs_info. This
wrapper will run into a separate process and should communicate its
result using the standard output. It expects the current directory as
its first argument.
_vbe_vcs_info() {
cd -q $1
vcs_info
print ${vcs_info_msg_0_}
}
The second step is to define a worker, vcs_info, and attach a
function to handle the result received from the wrapper. The
registered function calls zle reset-prompt to force a refresh of the
prompt with the updated information from ${vcs_info_msg_0_}.
source $ZSH/.../async.zsh
async_init
async_start_worker vcs_info
async_register_callback vcs_info _vbe_vcs_info_done
_vbe_vcs_info_done() {
local stdout=$3
vcs_info_msg_0_=$stdout
zle reset-prompt
}
The last step is to schedule the wrapper function in the worker
queue before displaying the prompt. This replaces the synchronous
invocation of vcs_info:
_vbe_vcs_precmd() {
async_flush_jobs vcs_info
async_job vcs_info _vbe_vcs_info $PWD
}
add-zsh-hook precmd _vbe_vcs_precmd
That’s it!
Without relying on vcs_info, it should be possible to have a better
experience by fetching the current branch name before retrieving the
more expensive information. However, without much effort, this simple
integration can make your prompt snappier! Have a look at the
complete code: it contains some small enhancements.