وضعیت گیت ۲.۰

هر کی اول صبح باشه git status تایپ کردن و سپس نوشیدن قهوه این کمک کوچک را دوست خواهد داشت. به خصوص زمانی که بسیاری از پروژه های وب به طور موازی در حال توسعه هستند، یکی ارزش آن را دارد نمای کلی فشرده: درخت کار کجا تمیز است، تغییرات ادغام نشده کجا آویزان است، و کجا منتظر کشش/فشار است؟ یک ابزار پوسته کوچک این کار را انجام می دهد - تا زمانی که به خوبی فضاها/یونیکد را در مسیرها کنترل کند و در کنترل از راه دور آویزان خفه نشود.


#!/usr/bin/env bash

set -Eeuo pipefail
export LC_ALL=C

# Check if a command exists (no output).
have() { command -v "$1" >/dev/null 2>&1; }

# Ensure we have a `sort` that supports -z (NUL-delimited) input.
SORT_BIN="sort"
if ! "$SORT_BIN" -z </dev/null 2>/dev/null; then
  if have gsort && gsort -z </dev/null 2>/dev/null; then
    SORT_BIN="gsort"
  else
    printf 'Error: This script requires "sort -z" (GNU coreutils). Install coreutils (gsort).\n' >&2
    exit 1
  fi
fi

# Use GNU `timeout` if available; otherwise try `gtimeout` (macOS); otherwise no timeout.
TIMEOUT_BIN="timeout"
if ! have "$TIMEOUT_BIN"; then
  if have gtimeout; then
    TIMEOUT_BIN="gtimeout"
  else
    TIMEOUT_BIN=""
  fi
fi

# Require git.
if ! have git; then
  printf 'Error: "git" not found.\n' >&2
  exit 1
fi

# Remove a leading "./" from a path for cleaner output.
trim_dot_slash() {
  case "$1" in
    ./*) printf '%s\n' "${1#./}" ;;
    *)   printf '%s\n' "$1" ;;
  esac
}

# Legend + divider (as requested)
printf '\n🟢: clean\n🟡: behind/ahead\n🔴: modified\n\n----------------------------------\n\n'

# Find all .git directories, NUL-delimited; sort NUL-delimited; iterate safely.
find . -type d -name .git -print0 \
| "$SORT_BIN" -z \
| while IFS= read -r -d '' gitdir; do
    repo="${gitdir%/.git}"
    display_path="$(trim_dot_slash "$repo")"

    # Skip anything that isn't a proper work tree (safety check).
    if ! git -C "$repo" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
      continue
    fi

    # Working tree status; include untracked files for a strict "red" signal.
    status_out="$(git -C "$repo" status --porcelain=v1 || true)"

    # Upstream divergence check (only if an upstream is configured).
    ahead=0
    behind=0
    if git -C "$repo" rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then
      # Refresh refs; protect with timeout so a hanging remote doesn't stall the loop.
      if [ -n "$TIMEOUT_BIN" ]; then
        "$TIMEOUT_BIN" 10s git -C "$repo" fetch --all --prune >/dev/null 2>&1 || true
      else
        git -C "$repo" fetch --all --prune >/dev/null 2>&1 || true
      fi
      # Count commits only on our side (ahead) and only on upstream's side (behind).
      ahead="$(git  -C "$repo" rev-list --count --left-only  HEAD...@{u} 2>/dev/null || echo 0)"
      behind="$(git -C "$repo" rev-list --count --right-only HEAD...@{u} 2>/dev/null || echo 0)"
    fi

    # Decide the signal:
    # - RED if the working tree isn't clean
    # - YELLOW if clean but ahead/behind of upstream
    # - GREEN otherwise
    if [ -n "$status_out" ]; then
      printf '🔴 %s\n' "$display_path"
    else
      if [ "${ahead:-0}" -gt 0 ] || [ "${behind:-0}" -gt 0 ]; then
        printf '🟡 %s\n' "$display_path"
      else
        printf '🟢 %s\n' "$display_path"
      fi
    fi
  done

فیلمنامه هنوز باید ... chmod +x ~/path/to/script.sh آن را قابل اجرا کنید و بتوانید یک نام مستعار برای صرفه‌جویی در تایپ‌های ارزشمند تنظیم کنید: در اینجا به [نام/نام مستعار/نام مستعار/نام مستعار/نام مستعار/نام مستعار/نام مستعار] او اضافه می‌کنید ~/.bashrc / ~/.zshrc / ~/.bash_profile ورودی alias gscan='bash /path/to/script.sh' بعلاوه. از آن به بعد، یک روش ساده gscan در دایرکتوری ریشه مورد نظر.

چند کلمه در مورد اینکه چرا اجرای دوم به طور قابل توجهی سریعتر است: در طول اجرای اول، سیستم فایل هنوز باید همه چیز را اسکن کند. پس از آن ابرداده و بسیاری است .git-ساختارها در حافظه پنهان صفحه سیستم عامل قرار گرفته‌اند. ارجاعات و نمودارهای کامیت نیز از قبل آماده شده‌اند. مورد بعدی fetch اکنون عمدتاً فقط دلتاهای کوچک را منتقل می‌کند. بدون داشبورد، بدون سربار - یک تصویر لحظه‌ای سریع از وضعیت مستقیماً در ترمینال.

بازگشت