git статусу 2.0

Эртең менен ким биринчи болсо 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-Түзүмдөр OS ядросунун бет кэшине конду, ал эми шилтемелер жана commit графиктери мурунтан эле жылытылган. Кийинки кадам... fetch Ал азыр негизинен кичинекей дельталарды гана өткөрөт. Куралдар тактасы жок, ашыкча чыгым жок – абалдын тез сүрөтү түздөн-түз терминалда.

Артка