|
1 | 1 | #!/bin/bash |
2 | | -# by http://github.com/jehiah |
3 | | -# this prints out some branch status (similar to the '... ahead' info you get from git status) |
| 2 | +# git-branch-status DEBUG |
| 3 | +# * originally by http://github.com/jehiah |
| 4 | +# * "s'all good!" message by http://github.com/kd35a |
| 5 | +# * ANSI colors by http://github.com/knovoselic |
| 6 | +# * column formatting and filters by http://github.com/bill-auger |
4 | 7 |
|
5 | | -# example: |
6 | | -# $ git branch-status |
7 | | -# dns_check (ahead 1) | (behind 112) origin/master |
8 | | -# master (ahead 2) | (behind 0) origin/master |
| 8 | +# this script prints out pretty git branch sync status reports |
9 | 9 |
|
10 | 10 |
|
11 | | -TOTAL_DIFFERENCES=0 |
12 | | -CGREEN='\033[1;32m' |
13 | | -CYELLOW='\033[1;33m' |
14 | | -CRED='\033[1;31m' |
15 | | -CEND='\033[0m' |
| 11 | +USAGE=<<USAGE |
| 12 | +usage: git-branch-status |
| 13 | + git-branch-status [-a | --all] |
| 14 | + git-branch-status [-h | --help] |
| 15 | + git-branch-status [-b | --branch [branch-name]] [branch-name] |
16 | 16 |
|
| 17 | + $ git-branch-status |
| 18 | + | dns_check | (ahead 1) | (behind 112) | origin/dns_check | |
| 19 | + | master | (ahead 2) | (behind 0) | origin/master | |
17 | 20 |
|
| 21 | + $ git-branch-status --all |
| 22 | + | a-local-branch | n/a | n/a | n/a | |
| 23 | + | a-remote-branch | (even) | (even) | origin/a-remote-branch | |
| 24 | + | dns_check | (ahead 1) | (behind 112) | origin/dns_check | |
| 25 | + | master | (ahead 2) | (behind 0) | origin/master | |
| 26 | +
|
| 27 | + $ git-branch-status -b |
| 28 | + $ git-branch-status --branch |
| 29 | + | current-branch | (ahead 2) | (behind 0) | origin/even-branch | |
| 30 | +
|
| 31 | + $ git-branch-status -h |
| 32 | + $ git-branch-status --help |
| 33 | + prints this message |
| 34 | +
|
| 35 | + $ git-branch-status specific-branch |
| 36 | + $ git-branch-status -b specific-branch |
| 37 | + $ git-branch-status --branch specific-branch |
| 38 | + | specific-branch | (ahead 2) | (behind 0) | origin/even-branch | |
| 39 | +USAGE |
| 40 | + |
| 41 | + |
| 42 | +# switches |
| 43 | +function current_branch() { echo $(git rev-parse --abbrev-ref HEAD) ; } |
| 44 | + |
| 45 | +function set_filter_or_die |
| 46 | +{ |
| 47 | + if [ "$(current_branch)" == "$1" ] || [ $(git branch | grep -G "^ $1$") ] ; then |
| 48 | + branch=$1 |
| 49 | + else echo "no such branch: '$1'" ; exit ; |
| 50 | + fi |
| 51 | +} |
| 52 | + |
| 53 | +if [ $1 ] ; then |
| 54 | + if [ "$1" == "-h" -o "$1" == "--help" ] ; then echo $USAGE ; exit ; |
| 55 | + elif [ "$1" == "-a" -o "$1" == "--all" ] ; then |
| 56 | + readonly SHOW_ALL=1 |
| 57 | + elif [ "$1" == "-b" -o "$1" == "--branch" ] ; then |
| 58 | + if [ $2 ] ; then set_filter_or_die $2 ; else branch=$(current_branch) ; fi ; |
| 59 | + else set_filter_or_die $1 |
| 60 | + fi |
| 61 | +fi |
| 62 | + |
| 63 | + |
| 64 | +# constants |
| 65 | +readonly SHOW_ALL_REMOTE=$(($SHOW_ALL + 0)) # also show branches that are up to date |
| 66 | +readonly SHOW_ALL_LOCAL=$(($SHOW_ALL + 0)) # also show branches that have no remote counterpart |
| 67 | +readonly CGREEN='\033[0;32m' |
| 68 | +readonly CYELLOW='\033[1;33m' |
| 69 | +readonly CRED='\033[0;31m' |
| 70 | +readonly CEND='\033[0m' |
| 71 | +readonly SPACER="|" |
| 72 | +readonly CAHEAD=$CYELLOW |
| 73 | +readonly CBEHIND=$CRED |
| 74 | +readonly CEVEN=$CGREEN |
| 75 | +readonly NO_RESULTS_MSG="${CEVEN}Everything is synchronized.$CEND" |
| 76 | + |
| 77 | + |
| 78 | +# variables |
| 79 | +n_total_differences=0 |
| 80 | +local_col_w=0 |
| 81 | +ahead_col_w=0 |
| 82 | +behind_col_w=0 |
| 83 | +remote_col_w=0 |
| 84 | +declare -a local_msgs=() |
| 85 | +declare -a ahead_msgs=() |
| 86 | +declare -a behind_msgs=() |
| 87 | +declare -a remote_msgs=() |
| 88 | +declare -a ahead_colors=() |
| 89 | +declare -a behind_colors=() |
| 90 | + |
| 91 | + |
| 92 | +# if [ $SHOW_ALL_REMOTE -eq 1 ] ; then echo "show diffs" ; else echo "no diffs" ; fi ; |
| 93 | +# if [ $SHOW_ALL_LOCAL -eq 1 ] ; then echo "show locals" ; else echo "no locals" ; fi ; |
| 94 | + |
| 95 | + |
| 96 | +# loop over all branches |
18 | 97 | while read local remote |
19 | 98 | do |
20 | | - [ -z "$remote" ] && continue |
21 | | - git rev-list --left-right ${local}...${remote} -- 2>/dev/null >/tmp/git_upstream_status_delta || continue |
22 | | - LEFT_AHEAD=$(grep -c '^<' /tmp/git_upstream_status_delta) |
23 | | - RIGHT_AHEAD=$(grep -c '^>' /tmp/git_upstream_status_delta) |
24 | | - TOTAL_DIFFERENCES=$(($LEFT_AHEAD + $RIGHT_AHEAD + $TOTAL_DIFFERENCES)) |
25 | | - MSG_LEFT_AHEAD="(ahead $LEFT_AHEAD)" |
26 | | - MSG_RIGHT_AHEAD="(behind $RIGHT_AHEAD)" |
27 | | - if [ "$LEFT_AHEAD" -ne 0 ]; then |
28 | | - MSG_LEFT_AHEAD="$CYELLOW$MSG_LEFT_AHEAD$CEND" |
29 | | - fi |
30 | | - if [ "$RIGHT_AHEAD" -ne 0 ]; then |
31 | | - MSG_RIGHT_AHEAD="$CRED$MSG_RIGHT_AHEAD$CEND" |
32 | | - fi |
33 | | - echo -e "$local $MSG_LEFT_AHEAD | $MSG_RIGHT_AHEAD $remote" |
| 99 | +# echo ; echo "$local <-> $remote IN" |
| 100 | +# if [ $branch ] && [ "$branch" != "$local" ] ; then echo "skipping branch '$local'" ; fi ; |
| 101 | +# if [ ! -z "$remote" ] ; then echo "has remote" ; else echo "no remote - bailing" ; fi ; |
| 102 | + |
| 103 | + # filter branches by name |
| 104 | + [ $branch ] && [ "$branch" != "$local" ] && continue |
| 105 | + |
| 106 | + # parse local<->remote sync status |
| 107 | + if [ ! -z "$remote" ] ; then |
| 108 | + status=$(git rev-list --left-right ${local}...${remote} -- 2>/dev/null) |
| 109 | + [ $(($?)) -eq 0 ] || continue |
| 110 | + n_ahead=$(echo $status | tr " " "\n" | grep -c '^<') |
| 111 | + n_behind=$(echo $status | tr " " "\n" | grep -c '^>') |
| 112 | + n_differences=$(($n_ahead + $n_behind)) |
| 113 | + n_total_differences=$(($n_total_differences + $n_differences)) |
| 114 | + |
| 115 | +# echo "SHOW_ALL_REMOTE=$SHOW_ALL_REMOTE n_ahead=$n_ahead n_behind=$n_behind n_total_differences =$n_total_differences" |
| 116 | + |
| 117 | + # filter branches by status |
| 118 | + [ "$SHOW_ALL_REMOTE" -eq 0 -a "$n_differences" -eq 0 ] && continue |
| 119 | + |
| 120 | + # color output |
| 121 | + if [ "$n_ahead" -ne 0 ] ; then ahead_color=$CAHEAD ; else ahead_color=$CEVEN ; fi ; |
| 122 | + if [ "$n_behind" -ne 0 ] ; then behind_color=$CBEHIND ; else behind_color=$CEVEN ; fi ; |
| 123 | + elif [ "$SHOW_ALL_LOCAL" -eq 1 ] ; then |
| 124 | + n_ahead="X" ; n_behind="X" ; remote="n/a" ; ahead_color="$CEVEN" ; behind_color="$CEVEN" |
| 125 | + else continue |
| 126 | + fi |
| 127 | + |
| 128 | + # populate lists |
| 129 | + local_msgs=( ${local_msgs[@]} "$local" ) |
| 130 | + ahead_msgs=( ${ahead_msgs[@]} "$n_ahead" ) |
| 131 | + behind_msgs=( ${behind_msgs[@]} "$n_behind" ) |
| 132 | + remote_msgs=( ${remote_msgs[@]} "$remote" ) |
| 133 | + ahead_colors=( ${ahead_colors[@]} "$ahead_color" ) |
| 134 | + behind_colors=( ${behind_colors[@]} "$behind_color" ) |
| 135 | + |
| 136 | +# echo "$local <-> $remote OUT" |
| 137 | +# echo "col_ws IN=[ ${#local} ${#n_ahead} ${#n_behind} ${#remote} ]" |
| 138 | +# echo "msg=*$local*$n_ahead*$n_behind*$remote*" |
| 139 | + |
| 140 | + # determine max column widths |
| 141 | + if [ ${#local} -gt $local_col_w ] ; then local_col_w=${#local} ; fi ; |
| 142 | + if [ ${#n_ahead} -gt $ahead_col_w ] ; then ahead_col_w=${#n_ahead} ; fi ; |
| 143 | + if [ ${#n_behind} -gt $behind_col_w ] ; then behind_col_w=${#n_behind} ; fi ; |
| 144 | + if [ ${#remote} -gt $remote_col_w ] ; then remote_col_w=${#remote} ; fi ; |
| 145 | + |
34 | 146 | done < <(git for-each-ref --format="%(refname:short) %(upstream:short)" refs/heads) |
35 | 147 |
|
36 | | -if [ "$TOTAL_DIFFERENCES" == 0 ]; then |
37 | | - echo -e "${CGREEN}Everything is synchronized.$CEND" |
38 | | -fi |
| 148 | +# echo "n_results=${#local_msgs[@]}" |
| 149 | +# compensate for "(ahead )" and "(behind )" to be appended |
| 150 | +ahead_col_w=$(($ahead_col_w + 8)) |
| 151 | +behind_col_w=$(($behind_col_w + 10)) |
| 152 | + |
| 153 | +# pretty print results |
| 154 | +for (( result_n = 0 ; result_n < ${#local_msgs[@]} ; result_n++ )) |
| 155 | +do |
| 156 | +# echo |
| 157 | + |
| 158 | +# pad "( 9 ahead)" like "( 99 ahead)" like "(999 ahead)" |
| 159 | +# ahead_pad_w=$(($ahead_col_w - ${#ahead_msgs[$result_n]} - 8)) |
| 160 | +# behind_pad_w=$(($behind_col_w - ${#behind_msgs[$result_n]} - 9)) |
| 161 | +# ahead_pad="'%"$ahead_pad_w"s'" |
| 162 | +# behind_pad="'%"$behind_pad_w"s'" |
| 163 | +# # echo "ahead_pad=$ahead_pad ahead_pad_w=$ahead_pad_w" |
| 164 | +# # echo "behind_pad_w=$behind_pad_w" |
| 165 | + |
| 166 | +# ahead_msg=$(printf "(${ahead_msgs[$result_n]} "$ahead_pad"ahead)") |
| 167 | +# behind_msg=$(printf "(${behind_msgs[$result_n]} "$behind_pad"behind)") |
| 168 | +# echo "'$head_msg' head_msg_len=${#head_msg}" |
| 169 | +# echo "'${ahead_msg}' ahead_msg_len=${#ahead_msg}" |
| 170 | + |
| 171 | +# behind_col_offset=$(($ahead_col_w - ${#ahead_msg} - 8 - $ahead_pad_w)) |
| 172 | +# remote_col_offset=$(($behind_col_w - ${#behind_msg} - 9 - $behind_pad_w)) |
| 173 | +# ahead_msg="("$ahead_pad" $ahead_msg ahead)" |
| 174 | +# behind_msg="("$behind_pad"$behind_msg behind)" |
| 175 | + |
| 176 | + # fetch and filter data |
| 177 | + local_msg="${local_msgs[$result_n]}" |
| 178 | + ahead_msg="(ahead ${ahead_msgs[$result_n]})" |
| 179 | + behind_msg="(behind ${behind_msgs[$result_n]})" |
| 180 | + remote_msg="${remote_msgs[$result_n]}" |
| 181 | + ahead_color="${ahead_colors[$result_n]}" |
| 182 | + behind_color="${behind_colors[$result_n]}" |
| 183 | + if [ "$remote_msg" == "n/a" ] ; then ahead_msg="n/a" ; ahead_color="" ; fi ; |
| 184 | + if [ "$remote_msg" == "n/a" ] ; then behind_msg="n/a" ; behind_color="" ; fi ; |
| 185 | + if [ "$ahead_msg" == "(0 ahead)" ] ; then ahead_msg="(even)" ; fi ; |
| 186 | + if [ "$behind_msg" == "(0 behind)" ] ; then behind_msg="(even)" ; fi ; |
| 187 | + |
| 188 | +# echo "local_msg='${local_msgs[$result_n]}'" |
| 189 | +# echo "ahead_msg='${ahead_msgs[$result_n]}'" |
| 190 | +# echo "behind_msg='${behind_msgs[$result_n]}'" |
| 191 | +# echo "remote_msgs='${remote_msgs[$result_n]}'" |
| 192 | + |
| 193 | +# echo "local_msg IN='$local_msg' (${#local_msg})" |
| 194 | +# echo "ahead_msg IN='$ahead_msg' (${#ahead_msg})" |
| 195 | +# echo "behind_msg IN='$behind_msg' (${#behind_msg})" |
| 196 | +# echo "remote_msgs IN='$remote_msg' (${#remote_msg})" |
| 197 | + |
| 198 | +# echo "ahead_color=$ahead_color" |
| 199 | +# echo "behind_color=$behind_color" |
| 200 | + |
| 201 | + # calculate column offsets |
| 202 | + local_col_offset=1 |
| 203 | + ahead_col_offset=$(($local_col_w - ${#local_msg})) |
| 204 | + behind_col_offset=$(($ahead_col_w - ${#ahead_msg})) |
| 205 | + remote_col_offset=$(($behind_col_w - ${#behind_msg})) |
| 206 | + end_col_offset=$(($remote_col_w - ${#remote_msg})) |
| 207 | + |
| 208 | +# echo "local_col_offset =$local_col_w - ${#local_msg} = $ahead_col_offset" |
| 209 | +# echo "ahead_col_offset =$ahead_col_w - ${#ahead_msg} = $behind_col_offset" |
| 210 | +# echo "remote_col_offset=$behind_col_w - ${#behind_msg} = $remote_col_offset" |
| 211 | +# echo "end_col_offset =$remote_col_w - ${#remote_msg} = $end_col_offset" |
| 212 | +# echo "col_ws OUT=[ $local_col_w $ahead_col_w $behind_col_w $remote_col_w ]" |
| 213 | +# echo "this_w OUT=[ ${#local_msg} ${#ahead_msg} ${#behind_msg} ${#remote_msg} ]" |
| 214 | +# echo "offsets =[ $ahead_col_offset $behind_col_offset $remote_col_offset $end_col_offset ]" |
| 215 | + |
| 216 | + # build output messages and print |
| 217 | + local_msg="%$(($local_col_offset))s $(echo -e $SPACER $local_msg)" |
| 218 | + ahead_msg="%$(($ahead_col_offset))s $(echo -e $SPACER $ahead_color$ahead_msg$CEND)" |
| 219 | + behind_msg="%$(($behind_col_offset))s $(echo -e $SPACER $behind_color$behind_msg$CEND)" |
| 220 | + remote_msg="%$(($remote_col_offset))s $(echo -e $SPACER $remote_msg)" |
| 221 | + end_msg="%$(($end_col_offset))s $SPACER" |
| 222 | + |
| 223 | +# echo "local_msg OUT='$local_msg'" |
| 224 | +# echo "ahead_msg OUT='$ahead_msg'" |
| 225 | +# echo "behind_msg OUT='$behind_msg'" |
| 226 | +# echo "remote_msgs OUT='$remote_msg'" |
| 227 | +# echo "msg=*$local_msg}*$ahead_msg}*$behind_msg}*$remote_msg}*" |
| 228 | + |
| 229 | + printf "$local_msg$ahead_msg$behind_msg$remote_msg$end_msg\n" |
| 230 | +done |
| 231 | + |
| 232 | +# print something if no diffs |
| 233 | +if [ "$n_total_differences" == 0 ] ; then echo -e $NO_RESULTS_MSG ; fi ; |
0 commit comments