zsh has excellent capabilities of supporting different version control systems, like git in its command line prompt. Setup is pretty convoluted and I’ll try to guide you through it to give you basic understanding of all the building blocks. You’ll be able to craft your own one.

I’ll show evolution of a command line prompt after each modification in .zshrc. I’ll assume ~/.git exists and has changes on the master branch. Current directory is set to ~/.ssh.

zsh has very extensive documentation. Two particularly useful pages are: zsh Prompt Expansion and zsh Version Control Information. You do not need to read them through, but they will be extremely useful when you’ll try to add some special flavor into your own prompt command.

Quickstart

You can set reasonable defaults from the zsh vcs_info Quickstart (don’t forget to add autoload -Uz vcs_info) and try to understand what does it mean later.

Show current user and directory in the command prompt

timothy@home:~/.ssh> 

zsh supports username %n, short hostname %m and directory %~ in prompt (other supported symbols):

  • Let’s show user@host:dir> prompt: PROMPT='%n@%m:%~> '

It’s pretty basic, but that’s only a beginning.

Show git (or any other version management system) info in the prompt

timothy@home: (git)-[master]-> 

  • Allow dynamic command prompt: setopt prompt_subst
  • Make sure that vcs_info function is available: autoload -Uz vcs_info
  • Update each time new prompt is rendered: function precmd() { vcs_info }
  • Show git info in the prompt: PROMPT='%n@%m:${vcs_info_msg_0_}> '

Now we can see that we’re within git repository.

Add repository path and path within repository to the prompt

timothy@home:/Users/timothy/(master).ssh> 

  • Show full path when outside of git: zstyle ':vcs_info:*' nvcsformats '%~'
  • Show base (.git) directory, current branch and path within a repo: zstyle ':vcs_info:*' formats '%R/(%b)%S'

All the information about available options check zsh vcs_info Configuration. It’s particularly useful to check for all expansion parameters available in different contexts.

That’s much better, we got back information about our current directory

Add information about uncommitted changes

timothy@home:/Users/timothy/(master).ssh!> 

  • Show “unsubmitted changes” mark: zstyle ':vcs_info:*' check-for-changes true
  • Add ! for unstaged changes: zstyle ':vcs_info:*' unstagedstr '!'
  • Add + for staged changes: zstyle ':vcs_info:*' stagedstr '+'
  • Render both marks if they are present: zstyle ':vcs_info:*' formats '%R/(%b)%S%u%c'

Good, we see ! as we have uncommitted changes, as expected.

Supporting merge and other special states

timothy@home:~/(rebase|20eeb6f... (3 applied)).ssh!> 

When git is in a special state (rebase or merge for git), branch %b information should be replaced with “current state” %a information. Also it’s a separate configuration string, actionformats instead of familiar formats one.

  • Support special state: zstyle ':vcs_info:*' actionformats '%R/(%a)%S%u%c'
  • Add miscellaneous data in a special state: zstyle ':vcs_info:*' actionformats '%R/(%a|%m)%S%u%c'

In git miscellaneous data is formatted as either %p (%n applied) or no patch applied (see /usr/share/zsh/$ZSH_VERSION/functions/VCS_INFO_get_data_git). Where %p is your full revision number e.g. 20eeb6fffcbb7260601af5181a6b4d5e46395c86, which is too long for the command line prompt. To shorten it in zsh to only 7 digits of hash I use %10>...>%p%<< instead, which roughly translates to: output %p, no longer than 10 symbols, shorten with ... string on the right side. %<< at the end is a marker for a string that should be 10 symbols long. See Conditional Substrings in Prompts for more details.

  • Shorten revision number during rebase: zstyle ':vcs_info:git:*' patch-format '%10>...>%p%<< (%n applied)'

Use ~ for the home directory once again

timothy@home:~/(master).ssh!> 

When we switched from zsh’s default %~ to git-specific %R we lost support for showing ~ instead of a home directory, let’s get it back!

zstyle ':vcs_info:*+set-message:*' hooks home-path
function +vi-home-path() {
  autoload -U regexp-replace
  hook_com[base]="${hook_com[base]/$HOME/~}"
}

Making it look nicer!

timothy@home:~/(master).ssh 

zsh supports colors, of course, but they are very verbose: %{%F{red}%} red text %{%f%}. Other colors: black, red, green, yellow, blue, magenta, cyan and white. Bold text is also supported: %{%B%} bold text %{%b%}. It’s recommended to use %{%E%} to reset colors right before the end of your prompt. Check Visual Effects for more info.

And, almost certainly UTF-8 is supported on your terminal so feel free to use Unicode symbols as well.

  • Example of stagedstr after making it nicer: zstyle ':vcs_info:*' stagedstr '%{%F{green}%B%}%{%b%f%}.

That’s it! Now you know everything you have to know to craft your own vcs_info-based prompt.

Good luck!

Full text of my current .zshrc