Skip to content

Commit 08d1ef7

Browse files
committed
add --remotes switch to show all remotes
1 parent 3425aa8 commit 08d1ef7

File tree

1 file changed

+189
-91
lines changed

1 file changed

+189
-91
lines changed

git-branch-status

Lines changed: 189 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#!/bin/bash
22

3-
# git-branch-status
4-
# * originally by http://github.com/jehiah
5-
# * "s'all good!" message by http://github.com/kd35a
6-
# * ANSI colors by http://github.com/knovoselic
7-
# * column formatting, filters, and usage by http://github.com/bill-auger
8-
9-
# this script prints out pretty git branch sync status reports
3+
# git-branch-status - this script prints out pretty git branch sync status reports
4+
# * originally by http://github.com/jehiah
5+
# * "s'all good!" message by http://github.com/kd35a
6+
# * ANSI colors by http://github.com/knovoselic
7+
# * formatting, filters, usage, and remotes by http://github.com/bill-auger
108

119

1210
read -r -d '' USAGE <<-'USAGE'
@@ -17,58 +15,108 @@ usage:
1715
git-branch-status [-b | --branch] [branch-name]
1816
git-branch-status [-d | --dates]
1917
git-branch-status [-h | --help]
18+
git-branch-status [-r | --remotes]
2019
git-branch-status [-v | --verbose]
2120
2221
examples:
2322
2423
# show only branches for which upstream HEAD differs from local
2524
$ git-branch-status
2625
| collab-branch | (behind 1) | (ahead 2) | origin/collab-branch |
27-
| feature-branch | (behind 0) | (ahead 2) | origin/feature-branch |
28-
| master | (behind 1) | (ahead 0) | origin/master |
26+
| feature-branch | (even) | (ahead 2) | origin/feature-branch |
27+
| master | (behind 1) | (even) | origin/master |
2928
30-
# show all branches - even those with no upstream and those up-to-date
29+
# show all branches - even those with no upstream or no local and those up-to-date
3130
$ git-branch-status -a
3231
$ git-branch-status --all
33-
| local-branch | n/a | n/a | (no upstream) |
34-
| master | (behind 1) | (ahead 0) | origin/master |
35-
| tracked-branch | (even) | (even) | origin/tracked-branch |
32+
| master | (even) | (ahead 1) | origin/master |
33+
| tracked-branch | (even) | (even) | origin/tracked-branch |
34+
| (no local) | n/a | n/a | origin/untracked-branch |
35+
| local-branch | n/a | n/a | (no upstream) |
36+
| master | (behind 1) | (ahead 1) | a-remote/master |
37+
| (no local) | n/a | n/a | a-remote/untracked-branch |
3638
3739
# show the current branch
3840
$ git-branch-status -b
3941
$ git-branch-status --branch
40-
| current-branch | (behind 0) | (ahead 2) | origin/current-branch |
42+
| current-branch | (even) | (ahead 2) | origin/current-branch |
4143
4244
# show a specific branch
4345
$ git-branch-status specific-branch
4446
$ git-branch-status -b specific-branch
4547
$ git-branch-status --branch specific-branch
46-
| specific-branch | (behind 0) | (ahead 2) | origin/specific-branch |
48+
| specific-branch | (even) | (ahead 2) | origin/specific-branch |
4749
4850
# show the timestamp of each HEAD
4951
$ git-branch-status -d
5052
$ git-branch-status --dates
51-
| 1999-12-31 master | (behind 2) | (ahead 0) | 2000-01-01 origin/master |
53+
| 1999-12-31 master | (behind 2) | (even) | 2000-01-01 origin/master |
5254
5355
# print this usage message
5456
$ git-branch-status -h
5557
$ git-branch-status --help
5658
"prints this usage message"
5759
60+
# show all remote branches - even those with no local
61+
$ git-branch-status -r
62+
$ git-branch-status --remotes
63+
| master | (behind 1) | (even) | a-remote/master |
64+
| (no local) | n/a | n/a | a-remote/untracked-branch |
65+
5866
# show all branches with timestamps (like -a -d)
5967
$ git-branch-status -v
6068
$ git-branch-status --verbose
61-
| 1999-12-31 local | n/a | n/a | (no upstream) |
62-
| 1999-12-31 master | (behind 1) | (ahead 0) | 2000-01-01 origin/master |
63-
| 1999-12-31 tracked | (even) | (even) | 2000-01-01 origin/tracked |
69+
| 1999-12-31 local | n/a | n/a | (no upstream) |
70+
| 1999-12-31 master | (behind 1) | (even) | 2000-01-01 origin/master |
71+
| 1999-12-31 tracked | (even) | (even) | 2000-01-01 origin/tracked |
6472
USAGE
6573

6674

75+
### constants ###
76+
77+
readonly MAX_COL_W=27 # should be => 12
78+
readonly CWHITE='\033[0;37m'
79+
readonly CGREEN='\033[0;32m'
80+
readonly CYELLOW='\033[1;33m'
81+
readonly CRED='\033[0;31m'
82+
readonly CEND='\033[0m'
83+
readonly CDEFAULT=$CWHITE
84+
readonly CAHEAD=$CYELLOW
85+
readonly CBEHIND=$CRED
86+
readonly CEVEN=$CGREEN
87+
readonly CNOUPSTREAM=$CRED
88+
readonly CNOLOCAL=$CRED
89+
readonly HRULE_CHAR='-'
90+
readonly JOIN_CHAR='_'
91+
readonly JOIN_REGEX="s/$JOIN_CHAR/ /"
92+
readonly STAR="*"
93+
readonly DELIM="|"
94+
readonly NO_UPSTREAM="(no${JOIN_CHAR}upstream)"
95+
readonly NO_LOCAL="(no${JOIN_CHAR}local)"
96+
readonly NO_RESULTS_MSG="Everything is synchronized"
97+
98+
99+
### variables ###
100+
n_total_differences=0
101+
local_w=0
102+
behind_w=0
103+
ahead_w=0
104+
remote_w=0
105+
declare -a local_msgs=()
106+
declare -a behind_msgs=()
107+
declare -a ahead_msgs=()
108+
declare -a remote_msgs=()
109+
declare -a local_colors=()
110+
declare -a behind_colors=()
111+
declare -a ahead_colors=()
112+
declare -a remote_colors=()
113+
114+
67115
### helpers ###
68116

69-
function get_refs
117+
function get_refs # (a_refs_dir)
70118
{
71-
git for-each-ref --format="%(refname:short) %(upstream:short)" refs/heads 2> /dev/null
119+
git for-each-ref --format="%(refname:short) %(upstream:short)" $1 2> /dev/null
72120
}
73121

74122
function get_status
@@ -117,70 +165,45 @@ function get_commit_msg # (a_commit_ref)
117165
git log -n 1 --format=format:"%s" $1
118166
}
119167

120-
121-
### switches ###
122-
123-
if [ $1 ] ; then
124-
if [ "$1" == "-a" -o "$1" == "--all" ] ; then readonly SHOW_ALL=1 ;
125-
elif [ "$1" == "-b" -o "$1" == "--branch" ] ; then
126-
if [ $2 ] ; then set_filter_or_die $2 ; else branch=$(current_branch) ; fi ;
127-
elif [ "$1" == "-d" -o "$1" == "--dates" ] ; then readonly SHOW_DATES=1 ;
128-
elif [ "$1" == "-h" -o "$1" == "--help" ] ; then echo "$USAGE" ; exit ;
129-
elif [ "$1" == "-v" -o "$1" == "--verbose" ]
130-
then readonly SHOW_ALL=1 ; readonly SHOW_DATES=1 ;
131-
else set_filter_or_die $1
132-
fi
133-
fi
134-
135-
136-
### constants ###
137-
138-
readonly SHOW_ALL_LOCAL=$(($SHOW_ALL + 0)) # also show branches that have no upstream
139-
readonly SHOW_ALL_REMOTE=$(($SHOW_ALL + 0)) # also show branches that are up to date
140-
readonly MAX_COL_W=27 # should be => 12
141-
readonly CWHITE='\033[0;37m'
142-
readonly CGREEN='\033[0;32m'
143-
readonly CYELLOW='\033[1;33m'
144-
readonly CRED='\033[0;31m'
145-
readonly CEND='\033[0m'
146-
readonly CDEFAULT=$CWHITE
147-
readonly CAHEAD=$CYELLOW
148-
readonly CBEHIND=$CRED
149-
readonly CEVEN=$CGREEN
150-
readonly CNOUPSTREAM=$CRED
151-
readonly JOIN_CHAR='_'
152-
readonly JOIN_REGEX="s/$JOIN_CHAR/ /"
153-
readonly STAR="*"
154-
readonly DELIM="|"
155-
readonly NO_UPSTREAM="(no${JOIN_CHAR}upstream)"
156-
readonly NO_RESULTS_MSG="Everything is synchronized"
168+
function printHRule # (rule_w)
169+
{
170+
printf " $(head -c $1 < /dev/zero | tr '\0' $HRULE_CHAR)\n"
171+
}
157172

158173

159-
### variables ###
174+
### business ###
160175

161-
n_total_differences=0
162-
local_w=0
163-
behind_w=0
164-
ahead_w=0
165-
remote_w=0
166-
declare -a local_msgs=()
167-
declare -a behind_msgs=()
168-
declare -a ahead_msgs=()
169-
declare -a remote_msgs=()
170-
declare -a local_colors=()
171-
declare -a behind_colors=()
172-
declare -a ahead_colors=()
173-
declare -a remote_colors=()
176+
function reset
177+
{
178+
n_total_differences=0
179+
local_w=0
180+
behind_w=0
181+
ahead_w=0
182+
remote_w=0
183+
local_msgs=()
184+
behind_msgs=()
185+
ahead_msgs=()
186+
remote_msgs=()
187+
local_colors=()
188+
behind_colors=()
189+
ahead_colors=()
190+
remote_colors=()
191+
}
174192

193+
function report # (a_local_branch_name a_remote_branch_name)
194+
{
195+
local=$1
196+
remote=$2
197+
does_local_exist=$(does_branch_exist $local_branch)
175198

176-
# loop over all branches
177-
while read local remote
178-
do
179-
# filter branches by name
199+
# filter branches per CLI arg
180200
[ $branch ] && [ "$branch" != "$local" ] && continue
181201

202+
# filter heads
203+
[ "$local" == "HEAD" ] && continue
204+
182205
# parse local<->remote sync status
183-
if [ $remote ] ; then
206+
if (($does_local_exist)) && [ $remote ] ; then
184207
status=$(get_status) ; (($?)) && continue ;
185208

186209
n_behind=$(echo $status | tr " " "\n" | grep -c '^>')
@@ -189,7 +212,7 @@ do
189212
n_total_differences=$(($n_total_differences + $n_differences))
190213

191214
# filter branches by status
192-
(($SHOW_ALL_REMOTE)) || (($n_differences)) || continue
215+
(($SHOW_ALL_UPSTREAM)) || (($n_differences)) || continue
193216

194217
# set data for branches with upstream
195218
local_color=$CDEFAULT
@@ -202,12 +225,18 @@ do
202225
else ahead_msg="(even)" ; ahead_color=$CEVEN ;
203226
fi
204227
remote_color=$CDEFAULT
205-
elif (($SHOW_ALL_LOCAL)) ; then
206-
# dummy data for branches with no upstream
228+
elif (($does_local_exist)) && [ -z $remote ] && (($SHOW_ALL_LOCAL)) ; then
229+
# dummy data for local branches with no upstream counterpart
207230
local_color=$CDEFAULT
208-
behind_msg="n/a" ; behind_color="$CDEFAULT" ;
209-
ahead_msg="n/a" ; ahead_color="$CDEFAULT" ;
210-
remote="$NO_UPSTREAM" ; remote_color=$CNOUPSTREAM ;
231+
behind_color="$CDEFAULT" ; behind_msg="n/a" ;
232+
ahead_color="$CDEFAULT" ; ahead_msg="n/a" ;
233+
remote_color=$CNOUPSTREAM ; remote="$NO_UPSTREAM" ;
234+
elif ! (($does_local_exist)) && [ $remote ] && (($SHOW_ALL_REMOTE)) ; then
235+
# dummy data for remote branches with no local counterpart
236+
local_color=$CNOLOCAL ; local="$NO_LOCAL" ;
237+
behind_color="$CDEFAULT" ; behind_msg="n/a" ;
238+
ahead_color="$CDEFAULT" ; ahead_msg="n/a" ;
239+
remote_color=$CDEFAULT
211240
else continue
212241
fi
213242

@@ -228,11 +257,10 @@ do
228257
if [ ${#behind_msg} -gt $behind_w ] ; then behind_w=${#behind_msg} ; fi ;
229258
if [ ${#ahead_msg} -gt $ahead_w ] ; then ahead_w=${#ahead_msg} ; fi ;
230259
if [ ${#remote_msg} -gt $remote_w ] ; then remote_w=${#remote_msg} ; fi ;
231-
done < <(get_refs)
260+
}
232261

233-
# pretty print results
234-
for (( result_n = 0 ; result_n < ${#local_msgs[@]} ; result_n++ ))
235-
do
262+
function printReportLine
263+
{
236264
# fetch data
237265
local_msg=$( echo ${local_msgs[$result_n]} | sed "$JOIN_REGEX" )
238266
behind_msg=$( echo ${behind_msgs[$result_n]} | sed "$JOIN_REGEX" )
@@ -258,9 +286,79 @@ do
258286
remote_msg="%$(( $remote_offset ))s $( echo -e $DELIM $remote_color$remote_msg$CEND)"
259287
end_msg="%$(( $end_offset ))s $DELIM"
260288
printf "$local_msg$behind_msg$ahead_msg$remote_msg$end_msg\n"
261-
done
289+
}
290+
291+
function printReport # (header)
292+
{
293+
n_notable_differences=${#local_msgs[@]}
294+
295+
# pretty print results
296+
printf "\n $1\n"
297+
if [ "$n_notable_differences" != "0" ]
298+
then rule_w=$(($local_w+$behind_w+$ahead_w+$remote_w+13))
299+
printHRule $rule_w
300+
for (( result_n = 0 ; result_n < $n_notable_differences ; result_n++ ))
301+
do printReportLine
302+
done
303+
printHRule $rule_w
304+
fi
262305

263-
# print something if no diffs (and some branches exist in this dir)
264-
if [ "$n_total_differences" == "0" -a "$(get_refs)" ]
265-
then echo -e "$CEVEN$NO_RESULTS_MSG$CEND"
306+
# print something if no diffs
307+
if [ "$n_total_differences" == "0" -a "$(get_refs)" ]
308+
then rule_w=$((${#NO_RESULTS_MSG}+4))
309+
printHRule $rule_w
310+
echo -e " $DELIM $CEVEN$NO_RESULTS_MSG$CEND $DELIM"
311+
printHRule $rule_w
312+
fi
313+
314+
reset
315+
}
316+
317+
318+
### main entry ###
319+
320+
# parse CLI switches
321+
if [ $1 ] ; then
322+
show_dates=0
323+
show_all=0
324+
show_all_local=0
325+
show_all_upstream=0
326+
show_all_remote=0
327+
if [ "$1" == "-a" -o "$1" == "--all" ] ; then show_all=1 ;
328+
elif [ "$1" == "-b" -o "$1" == "--branch" ] ; then
329+
if [ $2 ] ; then set_filter_or_die $2 ; else branch=$(current_branch) ; fi ;
330+
elif [ "$1" == "-d" -o "$1" == "--dates" ] ; then show_dates=1 ;
331+
elif [ "$1" == "-h" -o "$1" == "--help" ] ; then echo "$USAGE" ; exit ;
332+
elif [ "$1" == "-r" -o "$1" == "--remotes" ] ; then show_all_remote=1 ;
333+
elif [ "$1" == "-v" -o "$1" == "--verbose" ] ; then show_all=1 ;
334+
show_dates=1 ;
335+
else set_filter_or_die $1
336+
fi
337+
readonly SHOW_DATES=$show_dates
338+
readonly SHOW_ALL=$show_all
339+
readonly SHOW_ALL_LOCAL=$(($show_all + $show_all_local)) # also show branches that have no upstream
340+
readonly SHOW_ALL_UPSTREAM=$(($show_all + $show_all_upstream)) # also show branches that are up to date
341+
readonly SHOW_ALL_REMOTE=$(($show_all + $show_all_remote)) # also show branches that have no local
266342
fi
343+
344+
345+
# compare local branches status to their upstreams
346+
while read local upstream ; do report $local $upstream ; done < <(get_refs refs/heads) ;
347+
printReport "local <-> upstream"
348+
349+
350+
(($SHOW_ALL_REMOTE)) || exit
351+
352+
353+
# compare other remote branches status to local branches
354+
for remote_repo in `git remote`
355+
do
356+
while read remote_branch ; do
357+
local_branch=${remote_branch#$remote_repo/}
358+
upstream_branch=`git rev-parse --abbrev-ref $local_branch@{upstream} 2> /dev/null`
359+
360+
[ "$remote_branch" != "$upstream_branch" ] && report $local_branch $remote_branch
361+
done < <(get_refs refs/remotes/$remote_repo)
362+
363+
printReport "local <-> $remote_repo"
364+
done

0 commit comments

Comments
 (0)