An improved PS1 for Git in Bash

Last year I updated my bash prompt (PS1) to include the active git branch name.
A few months ago I added to the the active repository name.
So here’s an example of my PS1 when I’m in a git tracked directory on the master branch:

vid@server mydirectory (origin [master])$ 

And here it is when I have other remote repositories for the same project (bronze and heuristics);

vid@server mydirectory (bronze | heuristics | origin [master])$ 

And now once more when I’m on a branch (devel) that doesn’t exist on the available remotes:

vid@server mydirectory (bronze | origin [devel])$ 

That’s achieved with these functions: parse_git_branch and show-git-current-remotes-short.

First function parse_git_branch:

function parse_git_branch {
git branch 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* (.*)/ [1]/’
#git describe –contains –all HEAD
}

That pipes the ‘git branch’ command in to a sed replace and determines the current branch (the one with the *)

Next: show-git-current-remotes-short

function cur_git_branch { #returns the current branch; inline usage ex: git pull origin `cur_git_branch`
git branch 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* (.*)/1/’
#git describe –contains –all HEAD
}

function show-git-current-remotes-short(){ # This prints the matching remotes for the current branch name. Short version of show-git-current-remotes()
#!/bin/sh
if [[ -n “$( cur_git_branch )” ]] ; then
originalBranch=”$(git rev-parse –abbrev-ref HEAD)”
remoteMatchesArr=(); #Initiate remoteMatches array
branches=()
eval “$(git for-each-ref –shell –format=’branches+=(%(refname))’ refs/remotes/)” #remote branches.
for branch in “${branches[@]}”;
do
branchName=”$(basename ${branch})”
#set remoteName
oIFS=”$IFS”;
IFS=’/’ read -ra remoteArr <<< "$branch" remoteName="${remoteArr[2]}" if [[ $branchName == "$originalBranch" ]] ; then #capture the remote name remoteMatchesArr=("${remoteMatchesArr[@]}" "$remoteName") #Add remotes to array #remotes="$remotes $remoteName"; fi done IFS="$oIFS" echo ${remoteMatchesArr[@]} | sed 's/ / | /g' #delimit remotes with | fi #end if git dir unset remoteMathesArr } [/code]

Fhew!
That’s two functions. The show-git-current-remotes-short function requires the the cur_git_branch function.
cur_git_branch returns your current branch (using a different method than above) name or blank. So if you’re on a git branch ‘show-git-current-remotes-short’ will list the remotes that have a record of that branch.

Now, for the prompt


#PS1="u@h:W $(parse_git_branch)$ "
PS1="u@h:W ($(show-git-current-remotes-short)$(parse_git_branch))$ "

Here you can see I formerly only used 'parse_git_branch' and have since added 'show-git-current-remotes-short'.
This is the result:

vid@server mydirectory (bronze | heuristics | origin [master])$ 

Alternative:

You can display the current branch with the .git-prompt.sh's PS1:

if [ -f ~/.git-prompt.sh ]; then
. ~/.git-prompt.sh

#PS1='u@h W$(__git_ps1 " (%s)")$ '
PS1='u@h:W$(__git_ps1 " ($(show-git-current-remotes-short) [%s])")$ '
fi

OK. that checks if the file is there then run the script and return the branch.

Putting it all together

function cur_git_branch { #returns the current branch; inline usage ex: git pull origin `cur_git_branch`
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* (.*)/1/'
#git describe --contains --all HEAD
}
alias @branch=cur_git_branch # usage ex: git pull origin `@branch`
alias @br=@branch # usage ex: git pull origin `@br`

#-----------------------------------------------------------
# Git prompt
#-----------------------------------------------------------
# Git Bash shell command completion simple:
function parse_git_branch {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* (.*)/ [1]/'
#git describe --contains --all HEAD
}
#PS1="u@h:W $(parse_git_branch)$ "

#get current remotes:
function show-git-current-remotes-short(){ # This prints the matching remotes for the current branch name. Short version of show-git-current-remotes()
#!/bin/sh
if [[ -n "$( cur_git_branch )" ]] ; then
originalBranch="$(git rev-parse --abbrev-ref HEAD)"
remoteMatchesArr=(); #Initiate remoteMatches array
branches=()
eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/remotes/)" #remote branches.
for branch in "${branches[@]}";
do
branchName="$(basename ${branch})"
#set remoteName
oIFS="$IFS";
IFS='/' read -ra remoteArr <<< "$branch" remoteName="${remoteArr[2]}" if [[ $branchName == "$originalBranch" ]] ; then #capture the remote name remoteMatchesArr=("${remoteMatchesArr[@]}" "$remoteName") #Add remotes to array #remotes="$remotes $remoteName"; fi done IFS="$oIFS" echo ${remoteMatchesArr[@]} | sed 's/ / | /g' #delimit remotes with | fi #end if git dir unset remoteMathesArr } #Complex with .git-prompt.sh if [ -f ~/.git-prompt.sh ]; then . ~/.git-prompt.sh #PS1='u@h W$(__git_ps1 " (%s)")$ ' PS1='u@h:W$(__git_ps1 " ($(show-git-current-remotes-short) [%s])")$ ' else #PS1="u@h:W $(parse_git_branch)$ " PS1="u@h:W ($(show-git-current-remotes-short)$(parse_git_branch))$ " fi [/code]

Walla:
vid@server mydirectory (bronze | heuristics | origin [master])$

All this is valuable so that I can pull, push, fetch, merge and diff with different remotes with only a quick glance to see what my options are.

Comments
  • Max says:

    In your second screenshot,

    vid@server mydirectory (bronze | heuristics | origin [master])$

    Are bronze and heuristics remote branches or actually seperate repositories? If they are seperate repositories, what is the advantage of that instead of branching?

    • Vid says:

      Good question, they are separate repositories each with their own url, in fact; they could be on three different git servers: github, bitbucket, and a local git implementations like gitosis or stash.
      For my use case, ‘bronze’ and ‘heuristics’ are also users on the project and I named the remotes after the users so I could differentiate them.
      So we all pulled from essentially the same origin: master which was the project code base on github.

      As with the 3rd example above, both bronze and I had a ‘devel’ branch but heuristics did not.
      So looking at my prompt I knew I could diff my devel branch against the bronze version and compare our versions.

      When I realized that on any branch there could one or more remotes available that all have a branch of that same name, I knew I wanted that info front and center.

Leave a Comment