អ្នកណាដំបូងនៅពេលព្រឹក 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-Structures បានចុះចតនៅក្នុងឃ្លាំងសម្ងាត់ទំព័ររបស់ OS ខឺណែល ហើយឯកសារយោង និងក្រាហ្វិចត្រូវបានកំដៅឡើងរួចហើយ។ ជំហានបន្ទាប់... fetch ឥឡូវនេះវាភាគច្រើនបញ្ជូនតែដីសណ្តតូចៗប៉ុណ្ណោះ។ គ្មានផ្ទាំងគ្រប់គ្រង គ្មានពីលើក្បាល - រូបថតស្ថានភាពរហ័សដោយផ្ទាល់នៅក្នុងស្ថានីយ។