Diagnostics function, colorized (I tried to add guards so it is portable with terminals that do not support color):
git_diag() { local since="${1:-1 year ago}" local root repo branch # --- patterns --- local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}" local firefight_pattern="revert|hotfix|emergency|rollback" # --- colors --- local GREP_COLOR_MODE='never' if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]] && [[ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]]; then local BLACK=$(tput setaf 0) local RED=$(tput setaf 1) local GREEN=$(tput setaf 2) local YELLOW=$(tput setaf 3) local BLUE=$(tput setaf 4) local MAGENTA=$(tput setaf 5) local CYAN=$(tput setaf 6) local WHITE=$(tput setaf 7) local BOLD=$(tput bold) local DIM=$(tput dim 2>/dev/null || true) local RESET=$(tput sgr0) GREP_COLOR_MODE='always' else local BLACK='' RED='' GREEN='' YELLOW='' BLUE='' MAGENTA='' CYAN='' WHITE='' local BOLD='' DIM='' RESET='' fi local TITLE="$CYAN" local COLOR_COUNT="$CYAN" local COLOR_FILE="$YELLOW" if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then printf 'git_diag: not inside a Git repository\n' >&2 return 1 fi repo="${root##*/}" branch="$(git branch --show-current 2>/dev/null)" branch="${branch:-DETACHED}" _git_diag_fmt_count() { local count_color="$1" local text_color="$2" awk -v count_color="$count_color" -v text_color="$text_color" -v reset="$RESET" '{ c=$1 $1="" sub(/^ +/, "") printf " %s%10d%s %s%s%s\n", count_color, c, reset, text_color, $0, reset }' } printf '%s%sGit repo diagnostics%s\n' "$BOLD" "$TITLE" "$RESET" printf '%s%-11s%s %s\n' "$BOLD" "Repo:" "$RESET" "$repo" printf '%s%-11s%s %s\n' "$BOLD" "Branch:" "$RESET" "$branch" printf '%s%-11s%s %s\n' "$BOLD" "Timeframe:" "$RESET" "$since → now" printf '\n\n' printf '%s%s1) Most changed files%s\n' "$BOLD" "$TITLE" "$RESET" git log --since="$since" --format='' --name-only \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE" printf '\n%s%s2) Top contributors%s\n' "$BOLD" "$TITLE" "$RESET" git shortlog -sn --no-merges --since="$since" \ | head -n 10 \ | awk -v count_color="$COLOR_COUNT" -v reset="$RESET" '{ printf " %s%10d%s %s\n", count_color, $1, reset, substr($0, index($0,$2)) }' printf '\n%s%s3) Bug/fix hotspots%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$pattern" "$RESET" git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE" printf '\n%s%s4) Commit count by month%s\n' "$BOLD" "$TITLE" "$RESET" git log --since="$since" --format='%ad' --date=format:'%Y-%m' \ | sort \ | uniq -c \ | sort -k2r \ | awk -v count_color="$COLOR_COUNT" -v mag="$MAGENTA" -v reset="$RESET" ' { data[NR,1] = $2 data[NR,2] = $1 if (length($1) > max) max = length($1) } END { for (i = 1; i <= NR; i++) { printf " %s%10s%s %s%*d commits%s\n", mag, data[i,1], reset, count_color, max, data[i,2], reset } } ' printf '\n%s%s5) Firefighting commits%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$firefight_pattern" "$RESET" git log --since="$since" -i -E \ --grep="$firefight_pattern" \ --date=short \ --pretty=format:'%ad %h %s' \ | head -n 10 \ | awk -v mag="$MAGENTA" -v dim="$DIM" -v reset="$RESET" '{ date=$1 hash=$2 $1=$2="" sub(/^ */, "") printf " %s%-10s%s %s%-12s%s %s\n", mag, date, reset, dim, hash, reset, $0 }' \ | GREP_COLORS='ms=01;31' grep --color="$GREP_COLOR_MODE" -i -E "$firefight_pattern" }
git_diag() { local since="${1:-1 year ago}" local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}" local root repo branch if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then printf 'git_diag: not inside a Git repository\n' >&2 return 1 fi repo="${root##*/}" branch="$(git branch --show-current 2>/dev/null)" branch="${branch:-DETACHED}" _git_diag_fmt_count() { awk '{ c=$1 $1="" sub(/^ +/, "") printf " %10d %s\n", c, $0 }' } printf '============================================================\n' printf 'Git repo diagnostics\n' printf '%-11s%as\n' 'Repo:' "$repo" printf '%-11s%s\n' 'Branch:' "$branch" printf '%-11s%s\n' 'Timeframe:' "$since" printf '============================================================\n\n' printf '1) Most changed files (top 10)\n' git log --since="$since" --format='' --name-only \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count printf '\n2) Top 10 contributors (no merges, since %s)\n' "$since" git shortlog -sn --no-merges --since="$since" \ | head -n 10 \ | _git_diag_fmt_count printf '\n3) Bug/fix hotspots (top 10, matching: %s)\n' "$pattern" git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count printf '\n4) Commit count by month (since %s)\n' "$since" git log --since="$since" --format='%ad' --date=format:'%Y-%m' \ | sort \ | uniq -c \ | sort -k2r \ | awk ' { data[NR,1] = $2 data[NR,2] = $1 if (length($1) > max) max = length($1) } END { for (i = 1; i <= NR; i++) { printf " %10s %*d commits\n", data[i,1], max, data[i,2] } } ' printf '\n5) 10 most recent firefighting commits (revert|hotfix|emergency|rollback)\n' git log --since="$since" -i -E \ --grep='revert|hotfix|emergency|rollback' \ --date=short \ --pretty=format:'%ad %h %s' \ | head -n 10 \ | awk '{ date=$1 hash=$2 $1=$2="" sub(/^ */, "") printf " %-10s %-12s %s\n", date, hash, $0 }' \ | GREP_COLORS='ms=01;31' grep --color=always -i -E 'revert|hotfix|emergency|rollback' }
Diagnostics function, colorized (I tried to add guards so it is portable with terminals that do not support color):
Uncolorized diagnostics function (same, but without the colors):