Created
April 9, 2026 10:53
-
-
Save mekanics/27d25f81fbfdc60166372ca71d99823e 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
| #!/usr/bin/env bash | |
| # git-diagnostic.sh | |
| # Based on: https://piechowski.io/post/git-commands-before-reading-code/ | |
| # Runs five git diagnostics before reading a codebase. | |
| set -euo pipefail | |
| # ── helpers ──────────────────────────────────────────────────────────────────── | |
| RED=’\033[0;31m’ | |
| YELLOW=’\033[1;33m’ | |
| CYAN=’\033[1;36m’ | |
| BOLD=’\033[1m’ | |
| RESET=’\033[0m’ | |
| header() { | |
| echo | |
| echo -e “${CYAN}${BOLD}══════════════════════════════════════════════════════════${RESET}” | |
| echo -e “${CYAN}${BOLD} $1${RESET}” | |
| echo -e “${CYAN}${BOLD}══════════════════════════════════════════════════════════${RESET}” | |
| } | |
| warn() { echo -e “${YELLOW} ⚠ $1${RESET}”; } | |
| info() { echo -e “ $1”; } | |
| # ── guard ────────────────────────────────────────────────────────────────────── | |
| if ! git rev-parse –git-dir &>/dev/null; then | |
| echo -e “${RED}Not inside a git repository.${RESET}” | |
| exit 1 | |
| fi | |
| REPO_ROOT=$(git rev-parse –show-toplevel) | |
| echo -e “\n${BOLD}Repository:${RESET} $REPO_ROOT” | |
| # ── 1. What changes the most ─────────────────────────────────────────────────── | |
| header “1 / 5 · What Changes the Most (top 20 files, last year)” | |
| git log –format=format: –name-only –since=“1 year ago” | |
| | grep -v ‘^$’ | |
| | sort | uniq -c | sort -nr | head -20 | |
| | awk ‘{printf “ %5d %s\n”, $1, $2}’ | |
| info “” | |
| info “High-churn files that nobody wants to own = codebase drag.” | |
| info “Cross-reference with section 3 (bug clusters) for highest-risk files.” | |
| # ── 2. Who built this ────────────────────────────────────────────────────────── | |
| header “2 / 5 · Who Built This (all time vs. last 6 months)” | |
| echo -e “\n ${BOLD}All time:${RESET}” | |
| git shortlog -sn –no-merges | |
| | head -20 | |
| | awk ‘{printf “ %5d %s\n”, $1, substr($0, index($0,$2))}’ | |
| TOTAL_COMMITS=$(git shortlog -sn –no-merges | awk ‘{sum+=$1} END{print sum}’) | |
| TOP_COMMITS=$(git shortlog -sn –no-merges | head -1 | awk ‘{print $1}’) | |
| if [[ $TOTAL_COMMITS -gt 0 ]]; then | |
| TOP_PCT=$(( TOP_COMMITS * 100 / TOTAL_COMMITS )) | |
| if [[ $TOP_PCT -ge 60 ]]; then | |
| warn “Top contributor owns ${TOP_PCT}% of commits — high bus factor risk.” | |
| fi | |
| fi | |
| echo -e “\n ${BOLD}Last 6 months:${RESET}” | |
| RECENT=$(git shortlog -sn –no-merges –since=“6 months ago”) | |
| if [[ -z “$RECENT” ]]; then | |
| warn “No commits in the last 6 months.” | |
| else | |
| echo “$RECENT” | |
| | head -20 | |
| | awk ‘{printf “ %5d %s\n”, $1, substr($0, index($0,$2))}’ | |
| fi | |
| TOP_ALL=$(git shortlog -sn –no-merges | head -1 | sed ‘s/^[[:space:]]*[0-9]*[[:space:]]*//’) | |
| if [[ -n “$RECENT” ]] && ! echo “$RECENT” | grep -q “$TOP_ALL”; then | |
| warn “Top all-time contributor "$TOP_ALL" is absent from the last 6 months.” | |
| fi | |
| info “” | |
| info “Note: squash-merge workflows compress authorship — commits reflect who merged, not who wrote.” | |
| # ── 3. Where do bugs cluster ────────────────────────────────────────────────── | |
| header “3 / 5 · Where Do Bugs Cluster (top 20 files, fix/bug commits)” | |
| BUG_FILES=$(git log -i -E –grep=“fix|bug|broken” –name-only –format=’’ | |
| | grep -v ‘^$’ | |
| | sort | uniq -c | sort -nr | head -20) | |
| if [[ -z “$BUG_FILES” ]]; then | |
| warn “No commits matched fix|bug|broken — team may not use descriptive commit messages.” | |
| else | |
| echo “$BUG_FILES” | |
| | awk ‘{printf “ %5d %s\n”, $1, $2}’ | |
| info “” | |
| info “Files appearing in both this list and section 1 are your highest-risk code.” | |
| fi | |
| # ── 4. Is the project accelerating or dying ─────────────────────────────────── | |
| header “4 / 5 · Commit Velocity by Month (full history)” | |
| git log –format=’%ad’ –date=format:’%Y-%m’ | |
| | sort | uniq -c | |
| | awk ‘{printf “ %s %5d %s\n”, $2, $1, “·”}’ | |
| info “” | |
| info “Steady rhythm = healthy. Halved count in a single month = someone left.” | |
| info “Declining trend over 6-12 months = team losing momentum.” | |
| info “Spikes + quiet months = batch releases instead of continuous shipping.” | |
| # ── 5. How often is the team firefighting ───────────────────────────────────── | |
| header “5 / 5 · Firefighting Frequency (revert/hotfix/emergency, last year)” | |
| CRISIS=$(git log –oneline –since=“1 year ago” | |
| | grep -iE ‘revert|hotfix|emergency|rollback’ || true) | |
| if [[ -z “$CRISIS” ]]; then | |
| info “No revert/hotfix/emergency/rollback commits found in the last year.” | |
| info “Either the team is stable, or commit messages aren’t descriptive.” | |
| else | |
| COUNT=$(echo “$CRISIS” | wc -l | tr -d ’ ‘) | |
| echo “$CRISIS” | sed ‘s/^/ /’ | |
| echo | |
| if [[ $COUNT -gt 12 ]]; then | |
| warn “${COUNT} crisis commits in the last year (~every few weeks).” | |
| warn “Team likely doesn’t trust its deploy process: check tests, staging, rollback pipeline.” | |
| else | |
| info “${COUNT} crisis commit(s) in the last year — within normal range.” | |
| fi | |
| fi | |
| # ── done ────────────────────────────────────────────────────────────────────── | |
| echo | |
| echo -e “${BOLD}Done.${RESET} Cross-reference sections 1 & 3 to find your highest-risk files.” | |
| echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment