-
-
Save duub/2014d207d0b8086427df to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 ; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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: