To get a prompt which indicates Git-branch in Zsh

82,491

Solution 1

__git_ps1 is from git-completion.bash. In zsh you probably have to provide your own function to determine the current directories git branch. There are quite a few blog posts about a git prompt for zsh.

You just need:

  • a function to provide the branch name
  • enable prompt (command) substitution
  • add the function to your prompt

For example

git_prompt() {
 ref=$(git symbolic-ref HEAD | cut -d'/' -f3)
 echo $ref
}
setopt prompt_subst
PS1=$(git_prompt)%#
autoload -U promptinit
promptinit

Update: use the zsh vcs_info module instead of git_prompt()

setopt prompt_subst
autoload -Uz vcs_info
zstyle ':vcs_info:*' actionformats \
    '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{3}|%F{1}%a%F{5}]%f '
zstyle ':vcs_info:*' formats       \
    '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{5}]%f '
zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{3}%r'

zstyle ':vcs_info:*' enable git cvs svn

# or use pre_cmd, see man zshcontrib
vcs_info_wrapper() {
  vcs_info
  if [ -n "$vcs_info_msg_0_" ]; then
    echo "%{$fg[grey]%}${vcs_info_msg_0_}%{$reset_color%}$del"
  fi
}
RPROMPT=$'$(vcs_info_wrapper)'

Solution 2

A lot of these solutions seemed slow for me when mashing the return key, so here's an option that is basic and speedy:

parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}

setopt PROMPT_SUBST
PROMPT='%9c%{%F{green}%}$(parse_git_branch)%{%F{none}%} $ '

You'll get a prompt that looks like this: ~/dev/project (feature-branch) $

Solution 3

Here is an extended git prompt for zsh: zsh-git-prompt.

alt text

Solution 4

ko-dos's answer is great, but I prefer a slightly more git aware prompt than the one he uses. Specifically, I like staged, unstaged, and untracked file notifications in the prompt itself. Using his answer and the zsh vcs_info examples, I came up with the following:

setopt prompt_subst
autoload -Uz vcs_info
zstyle ':vcs_info:*' stagedstr 'M' 
zstyle ':vcs_info:*' unstagedstr 'M' 
zstyle ':vcs_info:*' check-for-changes true
zstyle ':vcs_info:*' actionformats '%F{5}[%F{2}%b%F{3}|%F{1}%a%F{5}]%f '
zstyle ':vcs_info:*' formats \
  '%F{5}[%F{2}%b%F{5}] %F{2}%c%F{3}%u%f'
zstyle ':vcs_info:git*+set-message:*' hooks git-untracked
zstyle ':vcs_info:*' enable git 
+vi-git-untracked() {
  if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
  [[ $(git ls-files --other --directory --exclude-standard | sed q | wc -l | tr -d ' ') == 1 ]] ; then
  hook_com[unstaged]+='%F{1}??%f'
fi
}


precmd () { vcs_info }
PROMPT='%F{5}[%F{2}%n%F{5}] %F{3}%3~ ${vcs_info_msg_0_} %f%# '

This creates a prompt that mimics the colorized output of git status -s (which can be configured in your .gitconfig file). A picture is perhaps most helpful here:

prompt

Compared with git status -s:

enter image description here

If you don't like colorized output, or would prefer some other character or prompt construction, just change the stagedstr, unstagedstr, and hook_com[unstaged] values in the above code.

Solution 5

I just redid mine since we have long branch names at work. This one will truncate with an ellipsis if it's more than 35 characters.

parse_git_branch() {
    git_status="$(git status 2> /dev/null)"
    pattern="On branch ([^[:space:]]*)"
    if [[ ! ${git_status} =~ "(working (tree|directory) clean)" ]]; then
        state="*"
    fi
    if [[ ${git_status} =~ ${pattern} ]]; then
      branch=${match[1]}
      branch_cut=${branch:0:35}
      if (( ${#branch} > ${#branch_cut} )); then
          echo "(${branch_cut}…${state})"
      else
          echo "(${branch}${state})"
      fi
    fi
}

setopt PROMPT_SUBST
PROMPT='%{%F{blue}%}%9c%{%F{none}%}$(parse_git_branch)$'

(I'm embarrassed at how proud I am of this.)

Share:
82,491
Michal aka Miki
Author by

Michal aka Miki

Vacare.

Updated on July 08, 2022

Comments

  • Michal aka Miki
    Michal aka Miki almost 2 years

    I run the following codes separately as my prompt unsuccessfully in .zshrc. This suggests me that apparently I do not have a program called __git_ps1. It is not in MacPorts.

    #1

    PROMPT="$(__git_ps1 " \[\033[1;32m\] (%s)\[\033[0m\]")\$"$
    

    #2

    PROMPT="$(__git_ps1 " (%s)")\$"$
    

    #3

    # Get the name of the branch we are on
    git_prompt_info() {
      branch_prompt=$(__git_ps1)
      if [ -n "$branch_prompt" ]; then
        status_icon=$(git_status)
        echo $branch_prompt $status_icon
      fi
    }
    
    # Show character if changes are pending
    git_status() {
      if current_git_status=$(git status | grep 'added to commit' 2> /dev/null); then
        echo "☠"
      fi
    }
    autoload -U colors
    colors
    setopt prompt_subst
    PROMPT='
    %~%{$fg_bold[black]%}$(git_prompt_info)
    → %{$reset_color%}'
    

    How can you get a prompt which shows the name of a Git-branch?

  • Anonigan
    Anonigan almost 15 years
    Do not use git-branch. It is porcelain, meant for UI, not for scripting. Use git-symbolic-ref and BR=${BR#refs/heads/}
  • Michal aka Miki
    Michal aka Miki almost 15 years
    @Jakub: Thank you for pointing that out! --- I just observed that git-branch causes bugs with non-git directories.
  • Justin Force
    Justin Force almost 12 years
    Love it! Perfect. Very nice work, and now a submodule in my own dotfiles repo. :)
  • drizzt
    drizzt over 11 years
    git_prompt is wrong, if you have a branch with / it does not work. Use cut -d'/' -f3- instead.
  • balki
    balki about 11 years
    Thanks!, this works. Can you please explain what those cryptic zstyle commands do?
  • harm
    harm about 11 years
    How does your approach compare to vcs_info? It seems that your script is reinventing the wheel? (Didn't stop me from using it though, I was unaware of vcs_info)
  • ntc2
    ntc2 about 11 years
    @balki The %F{n} enable ANSI color n for foreground, and %f disables foreground color. E.g., the formats format %F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{3}]%f becomes (%s)-[%b] if you ignore the colors. The %s gets replaced by the vc system (e.g. git) and the %b gets replaced by the current branch.
  • ntc2
    ntc2 about 11 years
    @balki The (sv[nk]|bzr) subpattern on the branchformat restricts it to svn, svk, and bzr. It means that those systems should use branch:revision instead of the default branch. Because of the enable line, bzr is not supported, so this bzr restriction is "dead code". The first three lines are copied verbatim from the ZSH docs, but the last line was added by someone else, which probably explains the dead code.
  • ntc2
    ntc2 about 11 years
    @balki The actionformats becomes (%s)-[%b|%a] ignoring colors. This format is used during special actions, with %a describing the action. This is the most useful feature IMHO: e.g. for git it tells when you are in the middle of a rebase (which I often forget about while trying to resolve merge conflicts).
  • Thanatos
    Thanatos over 10 years
    @Jakub Narębski: You can also do git symbolic-ref --short HEAD, which will remove the "refs/heads/" business for you.
  • Thomas Upton
    Thomas Upton almost 10 years
    This is a great git-specific use of vcs_info. One thing though: git status is slow. I used git ls-files --other --directory --exclude-standard | sed q | wc -l | tr -d ' ' instead, and it's much faster.
  • Christopher
    Christopher almost 10 years
    Nice modification. Updated accordingly.
  • Thomas Upton
    Thomas Upton almost 10 years
    The --directory flag might not actually be necessary. I found that it was annoying because git usually ignores empty directories.
  • szeryf
    szeryf over 9 years
    Had the same problem (i.e. empty directories ignored by git caused ?? to appear in the prompt). Fixed by adding --no-empty-directory flag to the git ls-files command.
  • David Faure
    David Faure over 9 years
    I've been using this for a long time, and it always worked well. Now however, after updating to zsh 5.0.7 and git 1.8.4, I get "fatal: Not a git repository" whenever going into a directory that is not a git repo. Any suggestions? (I see many discussions on detecting whether or not we're in a git repo, but I don't want to exit early if not, I also have svn repos... vcs_info was great at encapsulating all that...)
  • David Faure
    David Faure over 9 years
    Ah, found a solution: replacing the call to vcs_info with vcs_info 2>/dev/null
  • Timofey
    Timofey almost 9 years
    having trouble during sourcing: " unrecognized modifier `A'". zsh 4.2.6 (x86_64-redhat-linux-gnu). Is it a known issue?
  • ssokolow
    ssokolow over 4 years
    git symbolic-ref --short HEAD 2> /dev/null will get you an answer that requires less parsing.
  • Ev0oD
    Ev0oD over 3 years
    Repository no longer maintained - seems like some guys took over here: github.com/zsh-git-prompt/zsh-git-prompt editing answer to link to it
  • Ev0oD
    Ev0oD over 3 years
    Couldn't make it run neither with the repo I mention above. Found out ohmyzsh does it nicely, see stackoverflow.com/a/63919265/1920149
  • alper
    alper almost 3 years
    link for git prompt seems dead :(
  • SwiftMango
    SwiftMango over 2 years
    In the first simple solution, also use cut -d'/' -f3-, it will make sure to include the full name of the branch, if the branch name is like feature/xyz
  • Manish
    Manish over 2 years
    Where to add this code?
  • Maria Ines Parnisari
    Maria Ines Parnisari over 2 years
    @Manish in your ~/.zshrc file
  • Weston Ganger
    Weston Ganger almost 2 years
    Please note that the PROMPT must be in single quotes for the command to be re-run whenever changing directories
  • Weston Ganger
    Weston Ganger almost 2 years
    Please note that the PROMPT must be in single quotes for the command to be re-run whenever changing directories
  • Weston Ganger
    Weston Ganger almost 2 years
    Thank you so much for this tip about single quotes. My desire to use double quotes bit me here.
  • Dan Rosenstark
    Dan Rosenstark almost 2 years
    Like it is @WestonGanger or you're suggesting something else?