How to show git status info on the right side of the terminal?

Do you know if it is possible to configure the bash prompt to show the git status / branch info on the right side as zsh can do? This randomly screen shot from the internet shows what I mean.

Screen shot showing git status on the right side

  • GIT hook -> Python -> Bash: How to read user input?
  • calling git diff in pre-commit shell script
  • Progress bar for svn checkout in text mode
  • Git server's host key not cached in registry -
  • Getting a list of all unversioned files in a Git-controlled folder
  • WebDAV for Nginx in Archlinux
  • How to block cherry-pick to a specific branch on gerrit
  • Git clone Error for Poky from Yocto
  • Gradle- double-tier multi-project? In Eclipse with .git folders?
  • An error was raised by libgit2. Category = 21 (MergeConflict)
  • Gitolite permissions on branches
  • Git cherry pick creates duplicate commits
  • 4 Solutions collect form web for “How to show git status info on the right side of the terminal?”

    Try the following:

    PS1='$(printf "%*s\r%s" $(( COLUMNS-1 )) "[$(git branch 2>/dev/null | grep '^*' | sed s/..//)] $(date +%H:%M:%S)" "heipei@wavefront:$PWD$ ")'

    Note that you’ll never get behavior that exactly matches zsh one with bash only. In the above case I see the following differencies:

    1. Right part of the prompt is not cleared when you run a command (accept-line event in terms of zsh).
    2. Right part of the prompt will be cleared if you type something and then press <C-u> or <BS>.
    3. Right part of the prompt won’t be restored if you type something over it and then delete the text.
    4. Right part of the prompt won’t disappear if you type something over it, though text in this part will be overwritten.

    Today I built something like that in the following manner. Thorough testing has not been made yet…

    preprompt() {
      [ $rc -eq 0 ] && c=32
      PS1="\[$(color $c)\]$rc\[$(color 0)\] \t \w \$ "
      # right "prompt"
      # We cannot use $COLUMNS here, since in new shells the first prompt
      # will get garbled then. Seems like the correct value of COLUMNS is
      # in the shell init.
      printf "%`tput cols`s`tput cr`" "${USER}@${HOST}"

    The code below will create a prompt which looks like:

    bash prompt with git status on right

    It’s non-trival to do this in bash due to:

    • Readline mode string takes up characters before the prompt is printed, meaning that the printf solutions won’t work in some cases. Because of this:
    • Removing all ANSI CSI codes (eg colours) to correctly calculate the length of the printable right-hand-side prompt
    • Needing to use __git_ps1 to deal with git edge cases
    • __git_ps1 only outputting colour in certain circumstances, and only inside $PS1
    • Allowing colour in the __git_ps1 output while removing the \[ and \] characters from its output (which can’t be nested)
    • Wrapping the whole RHS prompt in \[ and \] to ensure that the prompt doesn’t do weird things when browsing / editing / completing commands

    # _options=$(shopt -op); set -exu # Save and set shell options for testing
    # Set the prompt #    Sourced from .bashrc
    # Select git info displayed, see /usr/lib/git-core/git-sh-prompt for more
    export GIT_PS1_SHOWCOLORHINTS=1           # Make pretty colours inside $PS1
    export GIT_PS1_SHOWDIRTYSTATE=1           # '*'=unstaged, '+'=staged
    export GIT_PS1_SHOWSTASHSTATE=1           # '$'=stashed
    export GIT_PS1_SHOWUNTRACKEDFILES=1       # '%'=untracked
    export GIT_PS1_SHOWUPSTREAM="verbose"     # 'u='=no difference, 'u+1'=ahead by 1 commit
    export GIT_PS1_STATESEPARATOR=''          # No space between branch and index status
    export GIT_PS1_DESCRIBE_STYLE="describe"  # Detached HEAD style:
    #  describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
    #  contains      relative to newer annotated tag (v1.6.3.2~35)
    #  branch        relative to newer tag or branch (master~4)
    #  default       exactly eatching tag
    # Sets prompt like:
    # ravi@boxy:~/prj/sample_app[exit]$                   master*% u= | 30 Apr 22:27
    _set_bash_prompt() {
      # Set left hand side of the prompt
      PS1="\u@\h:\w\$ "
      # Git status
      # Save current state of user shopt settings promptvars and extglob
      local user_shopt
      user_shopt=$(shopt -p promptvars extglob)
      # __git_ps1 usually returns literal text "${__git_ps1_branch_name}" rather
      # than the contained branch name, eg "master". This prevents calculating
      # the length of the printable characers in the RHS string (used to move the
      # cursor that many columns left from the terminal's right edge.) However if
      # "shopt promptvars" is unset, __git_ps1 it will include the dereferenced
      # branch name instead.
      shopt -qu promptvars
      # extglob is required for the ${variable//@(pattern)/} replacements
      shopt -qs extglob
      # Allow disabling git status and no error if __git_ps1 undefined
      if [[ ! -v _disable_git_prompt && $(type -t __git_ps1 2>/dev/null) == function ]]; then
        # __git_ps1 will only make pretty colours inside $PS1
        local old_PS1=$PS1
        __git_ps1 "" "" "%s" # force colour; no default round bracket (decorations)
        # Strip "\[" and "\[": non-printable character markers. __git_ps1 outputs
        # them however the whole of the RHS prompt needs to be included in these
        # markers, and they can't be nested.
      # Right hand side of prompt
      local rhs="" # String to be printed on the right hand side of terminal
      # Create a string like: "25 Apr 13:15"
      local date_time
      printf -v date_time "%(%e %b %H:%M)T" -1 # -1 is current time
      # Format the RHS prompt
      [[ -n $git ]] && rhs="$git | " #"
      # Strip ANSI CSI commands (eg colours) to enble counting the length of
      # printable characters, giving offset of cursor from terminal RHS edge (from
      # Neither bash not sed support lookbehind zero-length assertions, so it's not
      # possible to ignore "\\e", (ie a literal '\' followed by a literal 'e'), yet
      # still remove "\e" (ie ESC)
      local rhs_printable=${rhs//@(\\@(\[|]|[Ee]\[*([0-9;])[a-zA-Z]))/}
      # or, in using sed (but requires exec):
      # local rhs_printable=$(sed -e 's,\\[][]\|\\[Ee]\[\([0-9;]\)*[A-Za-z],,g' <<< "$rhs")
      # Reference:
      local Save='\e[s' # Save cursor position
      local Rest='\e[u' # Restore cursor to save point
      # Save cursor position, jump to (right hand edge minus N columns) where N is
      # the length of the printable RHS string. Print the RHS string, then return
      # to the saved position and print the LHS prompt.
      # Note: "\[" and "\]" are used so that bash can calculate the number of
      # printed characters so that the prompt doesn't do strange things when
      # command line editing/browsing/completion. Ensure that these are not nested.
      PS1="\[\e[0m${Save}\e[$((COLUMNS - ${#rhs_printable}))G${rhs}${Rest}\]${PS1}"
      eval "$user_shopt"
    # eval "$_options"; unset _options # Restore previous shell options from line 2

    One way would be to use tput to count the columns of your terminal, and subtrack the number of chars that are going to be printed left and right, then use that number as the number of spaces between the left and right text. Use printf to construct the line.

    quick example:

    left="[${status}]\u@\h:\w\$ "
    right="$(git symbolic-ref HEAD) $(date +%T)"
    spaces="$(( $(tput cols) - ${#left} - ${#right} ))"
    export PS1="$(printf "%s%${spaces}s\n" "$left" "$right")"
    Git Baby is a git and github fan, let's start git clone.