Skip to content

Instantly share code, notes, and snippets.

@duub
Forked from bill-auger/git-branch-status
Last active May 28, 2016 00:00
Show Gist options
  • Select an option

  • Save duub/2014d207d0b8086427df to your computer and use it in GitHub Desktop.

Select an option

Save duub/2014d207d0b8086427df to your computer and use it in GitHub Desktop.
#!/bin/bash
# git-branch-status
# * originally by http://github.com/jehiah
# * "s'all good!" message by http://github.com/kd35a
# * ANSI colors by http://github.com/knovoselic
# * column formatting and filters by http://github.com/bill-auger
# this script prints out pretty git branch sync status reports
read -r -d '' USAGE <<-'USAGE'
usage: git-branch-status
git-branch-status [-a | --all]
git-branch-status [-h | --help]
git-branch-status [-b | --branch [branch-name]] [branch-name]
$ git-branch-status
| dns_check | (ahead 1) | (behind 112) | origin/dns_check |
| master | (ahead 2) | (behind 0) | origin/master |
$ git-branch-status --all
| a-local-branch | n/a | n/a | n/a |
| a-remote-branch | (even) | (even) | origin/a-remote-branch |
| dns_check | (ahead 1) | (behind 112) | origin/dns_check |
| master | (ahead 2) | (behind 0) | origin/master |
$ git-branch-status -b
$ git-branch-status --branch
| current-branch | (ahead 2) | (behind 0) | origin/even-branch |
$ git-branch-status -h
$ git-branch-status --help
prints this message
$ git-branch-status specific-branch
$ git-branch-status -b specific-branch
$ git-branch-status --branch specific-branch
| specific-branch | (ahead 2) | (behind 0) | origin/even-branch |
USAGE
### helpers ###
function current_branch() { echo $(git rev-parse --abbrev-ref HEAD) ; }
function set_filter_or_die
{
if [ "$(current_branch)" == "$1" ] || [ $(git branch | grep -G "^ $1$") ] ; then
branch=$1
else echo "no such branch: '$1'" ; exit ;
fi
}
### switches ###
if [ $1 ] ; then
if [ "$1" == "-h" -o "$1" == "--help" ] ; then echo $USAGE ; exit ;
elif [ "$1" == "-a" -o "$1" == "--all" ] ; then
readonly SHOW_ALL=1
elif [ "$1" == "-b" -o "$1" == "--branch" ] ; then
if [ $2 ] ; then set_filter_or_die $2 ; else branch=$(current_branch) ; fi ;
else set_filter_or_die $1
fi
fi
### constants ###
readonly SHOW_ALL_REMOTE=$(($SHOW_ALL + 0)) # also show branches that are up to date
readonly SHOW_ALL_LOCAL=$(($SHOW_ALL + 0)) # also show branches that have no remote counterpart
readonly MAX_COL_W=25
readonly CGREEN='\033[0;32m'
readonly CYELLOW='\033[1;33m'
readonly CRED='\033[0;31m'
readonly CEND='\033[0m'
readonly SPACER="|"
readonly CAHEAD=$CYELLOW
readonly CBEHIND=$CRED
readonly CEVEN=$CGREEN
readonly NO_RESULTS_MSG="${CEVEN}Everything is synchronized.$CEND"
### variables ###
n_total_differences=0
local_col_w=0
ahead_col_w=0
behind_col_w=0
remote_col_w=0
declare -a local_msgs=()
declare -a ahead_msgs=()
declare -a behind_msgs=()
declare -a remote_msgs=()
declare -a ahead_colors=()
declare -a behind_colors=()
# loop over all branches
while read local remote
do
# filter branches by name
[ $branch ] && [ "$branch" != "$local" ] && continue
# parse local<->remote sync status
if [ $remote ] ; then
status=$(git rev-list --left-right ${local}...${remote} -- 2>/dev/null)
[ $(($?)) -eq 0 ] || continue
n_ahead=$( echo $status | tr " " "\n" | grep -c '^<')
n_behind=$(echo $status | tr " " "\n" | grep -c '^>')
n_differences=$(($n_ahead + $n_behind))
n_total_differences=$(($n_total_differences + $n_differences))
# filter branches by status
[ "$SHOW_ALL_REMOTE" -eq 0 -a "$n_differences" -eq 0 ] && continue
# color output
if [ "$n_ahead" -ne 0 ] ; then ahead_color=$CAHEAD ; else ahead_color=$CEVEN ; fi ;
if [ "$n_behind" -ne 0 ] ; then behind_color=$CBEHIND ; else behind_color=$CEVEN ; fi ;
elif [ "$SHOW_ALL_LOCAL" -eq 1 ] ; then
# dummy data for locals
n_ahead="X" ; n_behind="X" ; remote="n/a" ; ahead_color="$CEVEN" ; behind_color="$CEVEN"
else continue
fi
# populate lists
local=${local:0:$MAX_COL_W} ; remote=${remote:0:$MAX_COL_W} ;
local_msgs=( ${local_msgs[@]} "$local" )
ahead_msgs=( ${ahead_msgs[@]} "$n_ahead" )
behind_msgs=( ${behind_msgs[@]} "$n_behind" )
remote_msgs=( ${remote_msgs[@]} "$remote" )
ahead_colors=( ${ahead_colors[@]} "$ahead_color" )
behind_colors=( ${behind_colors[@]} "$behind_color" )
# determine max column widths
if [ ${#local} -gt $local_col_w ] ; then local_col_w=${#local} ; fi ;
if [ ${#n_ahead} -gt $ahead_col_w ] ; then ahead_col_w=${#n_ahead} ; fi ;
if [ ${#n_behind} -gt $behind_col_w ] ; then behind_col_w=${#n_behind} ; fi ;
if [ ${#remote} -gt $remote_col_w ] ; then remote_col_w=${#remote} ; fi ;
done < <(git for-each-ref --format="%(refname:short) %(upstream:short)" refs/heads)
# compensate for "(ahead )" and "(behind )" to be appended
ahead_col_w=$(( $ahead_col_w + 8 ))
behind_col_w=$(( $behind_col_w + 9 ))
# pretty print results
for (( result_n = 0 ; result_n < ${#local_msgs[@]} ; result_n++ ))
do
# fetch and filter data
local_msg="${local_msgs[$result_n]}"
ahead_msg="(ahead ${ahead_msgs[$result_n]})"
behind_msg="(behind ${behind_msgs[$result_n]})"
remote_msg="${remote_msgs[$result_n]}"
ahead_color="${ahead_colors[$result_n]}"
behind_color="${behind_colors[$result_n]}"
if [ "$remote_msg" == "n/a" ] ; then ahead_msg="n/a" ; ahead_color="" ; fi ;
if [ "$remote_msg" == "n/a" ] ; then behind_msg="n/a" ; behind_color="" ; fi ;
if [ "$ahead_msg" == "(0 ahead)" ] ; then ahead_msg="(even)" ; fi ;
if [ "$behind_msg" == "(0 behind)" ] ; then behind_msg="(even)" ; fi ;
# calculate column offsets
local_col_offset=1
ahead_col_offset=$(( $local_col_w - ${#local_msg} ))
behind_col_offset=$(( $ahead_col_w - ${#ahead_msg} ))
remote_col_offset=$(( $behind_col_w - ${#behind_msg} ))
end_col_offset=$(( $remote_col_w - ${#remote_msg} ))
# build output messages and print
local_msg="%$(($local_col_offset))s $( echo -e $SPACER $local_msg)"
ahead_msg="%$(($ahead_col_offset))s $( echo -e $SPACER $ahead_color$ahead_msg$CEND)"
behind_msg="%$(($behind_col_offset))s $(echo -e $SPACER $behind_color$behind_msg$CEND)"
remote_msg="%$(($remote_col_offset))s $(echo -e $SPACER $remote_msg)"
end_msg="%$(($end_col_offset))s $SPACER"
printf "$local_msg$ahead_msg$behind_msg$remote_msg$end_msg\n"
done
# print something if no diffs
if [ "$n_total_differences" == 0 ] ; then echo -e $NO_RESULTS_MSG ; fi ;
@bill-auger
Copy link

i have created a repo for this script on github in order to have a proper issue tracker - all further development and communications will take place there - feel free to clone, fork, star , or watch the github repo -->

https://github.com/bill-auger/git-branch-status/

this script is also now icluded in jwiegley's git-scripts collection but please direct comments, bug reports, and feature requests to the upstream issue tracker

@duub -
could you please merge my fork into yours - this will replace the script body with a link to the latest upstream repo on github like so:

git remote add bill-auger-gist https://gist.github.com/9335fe2633eae38d3070.git
git fetch bill-auger-gist
git merge bill-auger-gist/master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment