Kiu ajn estas la unua matene git status Ĉiu, kiu tajpas kaj poste trinkas kafon, amos ĉi tiun malgrandan helpilon. Precipe dum la disvolvado de multaj retprojektoj samtempe, kompakta superrigardo estas valorega: Kie la laborarbo estas pura, kie estas nekunfanditaj ŝanĝoj, kaj kie estas atendanta tiro/puŝo? Malgranda ŝela ilo estas ĉio, kion vi bezonas - kondiĉe ke ĝi traktas spacetojn/Unikodon en padoj fortike kaj ne sufokiĝas pro blokitaj teleregiloj.
#!/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
La manuskripto ankoraŭ bezonas esti... chmod +x ~/path/to/script.sh igi ĝin efektivigebla kaj povas agordi kaŝnomon por ŝpari valoran tajpadon: Ĉi tie vi aldonas al lia ~/.bashrc / ~/.zshrc / ~/.bash_profile la eniro alias gscan='bash /path/to/script.sh' krome. De tiam, simpla gscan en la dezirata radika dosierujo.
Unu kialo, kial la dua kuro estas rimarkeble pli rapida: Dum la unua kuro, la dosiersistemo ankoraŭ devas skani ĉion; poste, metadatenoj kaj multaj aliaj aferoj jam estas prilaboritaj. .git-Strukturoj alvenis en la paĝkaŝmemoron de la operaciumkerno, kaj referencoj kaj konfirmografoj jam varmiĝis. La sekva paŝo... fetch Ĝi nun plejparte nur elsendas malgrandajn deltojn. Neniu instrumentpanelo, neniu kromprogramo - rapida statusa momentfoto rekte en la terminalo.