Ubuntu – script to show git branch in bash no longer works on ubuntu 18.04

bashbashrcgitprompt

In my 16.04 installation I put this in my ~/.bashrc file:

#Show git branch in commandline
parse_git_branch() {
     git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u:\[\033[01;34m\]\w\[\033[00m\]\$(parse_git_branch)\[\033[00m\] $ "

It showed a prompt like this:

user:~/myrepo (master) $

But when I do the same on 18.04 the prompt looks like this instead:

user:~/myrepo $ 

How do I get it to work in 18.04?

$ printf "%q\n" "$PS1" "$PROMPT_COMMAND" "$0" "$SHELL"
\\\[\\033\[01\;32m\\\]\\u:\\\[\\033\[01\;34m\\\]\\w\\\[\\033\[00m\\\]\$\(parse_git_branch\)\\\[\\033\[00m\\\]\ \$\ 
''
bash
/bin/bash

I’m using sed (GNU sed) 4.4 and GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu). This is a "fresh" installation, so there is nothing additional in .bashrc.

Best Answer

Although you already solved the problem, I'd like to introduce the solution already shipped with git:

Together with git the file /usr/lib/git-core/git-sh-prompt gets installed. Years ago it was in the contrib directory but meanwhile it made it into the official paths. The file isn't meant to be executed (in fact, it doesn't have x flags) but rather to be sourced from the .bashrc. It defines some functions to handle a pretty prompt, the most prominent being __git_ps1.

You can add the following lines to your .bashrc:

source /usr/lib/git-core/git-sh-prompt
export PS1="${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u:\[\033[01;34m\]\w\[\033[00m\]\$(__git_ps1)\[\033[00m\] $ "

The top of the file /usr/lib/git-core/git-sh-prompt gives some description of what else can be done. My version says 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh). but this is not necessary (the instruction is obsolete).

You may also set some environment variables to alter the function's behaviour. I, for instance, use

export GIT_PS1_SHOWDIRTYSTATE=yes

The result then looks like:

# clean
pduck:~/oss/rsyslog (master) $ 

or

# dirty
pduck:~/oss/rsyslog (master *) $ 

or

# something added to index
pduck:~/oss/rsyslog (master +) $ 

or

# in a completely fresh repo
pduck:~/oss/xxx (master #) $ 

Btw: The "proper" way to get the current branch is not to parse git branch's output as that may change with new git versions. git branch is a so-called porcelain command which means its output is nice and pretty but not guaranteed to stay the same with different versions. The git guys thus recommend plumbing tools for scripting. With plumbing the current branch can be determined with

if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
    current_branch=$(git symbolic-ref --quiet --short HEAD || git rev-parse --short HEAD)
else
    current_branch=""
fi

The first assignment works if HEAD is a symbolic reference (that is: a branch or tag is checked out). If you checked out something that has no label (e.g. git checkout HEAD^^), then it fails and we use git rev-parse --short HEAD instead to show the SHA1. The if checks whether we are in a git working directory at all (because else the commands don't make any sense).