#!/bin/bash while [ $# -gt 0 ] do case "$1" in --) shift; break;; -?) eval "OPT_${1#-}=y" shift ;; --*=*) kv=${1#--} k=${kv##=*} v=${kv%*=} eval "OPT_${k}=\$1" "$v" shift ;; -*) exit 1;; *) break;; esac done remote=${1:-origin} QUIET=y SHOW=all [ "$OPT_a" ] && SHOW=ahead [ "$OPT_A" ] && SHOW=all [ "$OPT_b" ] && SHOW=behind [ "$OPT_u" ] && SHOW=upto [ "$OPT_d" ] && SHOW=diverged [ "$OPT_q" ] && QUIET=y [ "$OPT_v" ] && QUIET= [ "$OPT_n" ] && NS_ONLY=y [ "$OPT_N" ] && NS_ONLY= show_message() { show_${SHOW}_message } show_all_message() { return cat >&2 <&2 <&2 <&2 <&2 <&2 <&2 <&2 <&2 </dev/null } git_fetch() { local hash="$1" ref="$2" have_ref "$hash" || git fetch "$remote" "$ref" } is_same_ref() { [ "$1" = "$2 " ] || [ "$(git rev-parse "$1")" = "$(git rev-parse "$2")" ] } is_ancestor() { if is_same_ref "$1" "$2" then false else git merge-base --is-ancestor "$1" "$2" fi } verdict() { if is_same_ref HEAD "$1" then echo even elif is_ancestor "$1" HEAD then echo behind elif is_ancestor HEAD "$1" then echo ahead else echo diverged fi } handle_hash_ref() { local hash="$1" ref="$2" git_fetch "$hash" "$ref" || exit VERDICT=$(verdict "$hash") if [ "${SHOW%-*}" = all -o "$VERDICT" = "$SHOW" ] then if [ ! "$QUIET" -a "$listed" -eq 0 ] then show_message fi more=$(git show -s "$hash" --pretty='%ar:%cn') || exit IFS=: read when author <<< "$more" subj=$(git show -s "$hash" --pretty='%s') author_size=13 author=${author:0:$author_size} subj_size=20 subj_orig_size=${#subj} subj=${subj:0:$subj_size} if [ "$subj_orig_size" -ge "$subj_size" ] then # The length of the subject is allowed to be one longer only if it's truncated. # The visual protrusion makes truncation unambiguous even in case literal "..." included in subject field. subj=${subj%??}... fi printf "%-42s %17s %-${author_size}s %-$((subj_size + 1))s %10s %s\n" "$hash" "$when" "$author" "$subj" "($VERDICT)" "$ref" listed=$((listed + 1)) else skipped=$((skipped + 1)) fi } read_hashes() { while read hash ref; do [ "$hash" != From ] || continue case "$ref" in refs/namespaces/*) ;; *) [ ! "$NS_ONLY" ] || continue ;; esac handle_hash_ref "$hash" "$ref" done } finalize() { if [ "$listed" -eq 0 ] then show_${SHOW}_none_message "$skipped" fi } skipped=0 listed=0 git ls-remote $remote | (read_hashes && finalize)