souping up your bash prompt
Summary for the impatient/expert
Details
Download bash script
Screenshot
Supplementary code
This document describes how to get command completion as well as a souped up bash prompt.
Git comes with a bash script in the 'contrib/completion' directory which takes
care of command completion as well as displaying the current branch name in your
PS1 (primary bash prompt). We use that as a basis, and -- without digging
inside of it (meaning you can upgrade that without worry) -- we add more
functionality.
__git_ps1 sends back. That is, completion,
branch name, and branch state text come from __git_ps1, in
'contrib/completion/git-completion.bash' in the git source treebut when you
it shows a color-coded count of files in various states: unmerged (bold
red), untracked (blue), modified (red), and staged (green). In addition,
the branch name reported by __git_ps1 is also colored (for example,
bright red when the head is detached).
The implementation is either a neat and elegant hack or kludge city, depending on whom you ask :)
For a while, I've wanted a quick summary of git status -- how many files are
staged (git added), modified, untracked, unmerged, etc. I've also wanted a
quick indication of whether the current HEAD is a detached head, etc. And I
wanted it to be as compact as possible.
But... I didn't want 'git status' to run on every prompt -- that would be too expensive for some of the msysgit users I support. I wanted this extra piece to kick in only when
That last part was tough, but I'm pleased that my solution not only works, it even works on msysgit so my Windows users are happy too!
The part that computes the status and summarises it with colored numbers is a
hacked up version of git://github.com/lvv/git-prompt.git), and you can
download it here. And here's a
syntax colored version to quickly
view on a browser. You're expected to source it into your .bashrc; it'll
take care of sourcing the git-supplied one, which it looks for in $HOME.
After that, you need to include the snippet of bash code given in this section. I used to have all this in one file, but the code to detect the quick-double-enter has uses outside git also, so I separated that logic from the 'git status colorisation' stuff.
[Update 2009-03-19: the screenshot is not quite current but will suffice to give you the general idea]
Someone asked for a screenshot so here is
one; it should give you enough of an idea.
You can see the extra information (namely, the output of __git_ps1 being
colored, and a few numbers after that in different colors at certain places:
__git_ps1 changes (this is the bit inside
parentheses)The color choices retain the colors that git status shows (with git config
--global color.ui true) for staged and modified files -- this is green and
red, respectively. git status uses red for untracked files also, but we use
blue. Unmerged files are magenta.
I didn't show changing to another directory and coming back -- that would also trigger the extra info. I also didn't show all 4 colors (staged, modified, untracked, unmerged) at the same time but I'm sure you get the idea.
The following code contains the hack to do something different if you hit
enter twice in quick succession. It need to be run via bash's
PROMPT_COMMAND mechanism -- do not call it directly from PS1 using the
$(bash_command) syntax. That syntax runs things in a sub-shell, which won't
let you maintain state.
You'll notice there's git-specific stuff in there. The idea is that if you need some other information (like, perhaps, percentage disk free, or maybe system load, if you don't have conky or gkrellm), then that also can use the same mechanism; you'd just add bits of code in here, piggy-backing on the logic already present to make things run only sometimes instead of on every prompt.
Of course you can change the PS1=[...] lines however you like.
export PROMPT_COMMAND=__ps1_plus
__ps1_plus()
{
# elegant hack or extreme kludgery? You decide...
# I wanted a way to see a long prompt very conveniently, but
# not on *every* prompt -- hitting enter twice in quick succession at the
# bash prompt was about as much as I was willing to do :-)
# The hack works by remembering the $SECONDS value at the end of each
# unsuccesful invocation. When the next invocation still has the same
# $SECONDS, you know the user hit enter twice, so you do the 'git status'
# stuff.
# In addition, of course, if the PWD or the output of __git_ps1 itself
# changed, that also triggers the extra stuff.
local gitps1
declare -F __git_ps1 >/dev/null && gitps1=$(__git_ps1)
if [[ $__ps1_state != $PWD/$gitps1 || $__ps1_plus_last -eq $SECONDS ]]
then
__ps1_state=$PWD/$gitps1
# if enhanced PS1 builder exists call it to set __git_ps1_text;
# otherwise default is the git-distributed one
__git_ps1_text=$gitps1
declare -F __git_ps1_plus >/dev/null && __git_ps1_plus
echo -n -e '\e]0;'${HOSTNAME%%.*}:
[[ $PWD == $HOME ]] && echo -n '~' || echo -n $(basename $PWD)
echo -n -e '\a'
PS1='\[\e[4m\e[32m\]\t \h:\W$__git_ps1_text\[\e[m\] \$ '; [[ $EUID == 0 ]] &&
PS1='\[\e[4m\e[31m\]\t \h:\W$__git_ps1_text\[\e[m\] \$ '
else
PS1='\[\e[4m\e[32m\]\t\[\e[m\] \$ '; [[ $EUID == 0 ]] &&
PS1='\[\e[4m\e[32m\]\t\[\e[m\] \$ '
fi
__ps1_plus_last=$SECONDS
}
and this is a copy of the v1.6.1 version of git-completion.bash from the git source tree; you probably have it already