add timeout to git operations

This commit is contained in:
fatalerrors
2026-05-28 11:31:20 +02:00
parent d9a62cf2a8
commit a33aa5f6be
3 changed files with 50 additions and 13 deletions

View File

@@ -356,6 +356,7 @@ The twelve available `PROMPT_COLOR_*` keys are:
[prompt]
PROMPT_SHOW_GIT = 1
PROMPT_SHOW_GIT_STATUS = 1
PROMPT_GIT_TIMEOUT = 2
PROMPT_SHOW_CONDA = 1
PROMPT_SHOW_VENV = 1
PROMPT_SHOW_SESSION = 1
@@ -366,10 +367,11 @@ When enabled, the top prompt bar appends:
- `git:<branch>` when inside a Git repository
- `git:<branch>*` when local changes are present
- `git:<branch> +N/-M` when ahead/behind upstream
- `git:<branch>?` when `git diff` or `git rev-list` exceeded `PROMPT_GIT_TIMEOUT`
- `conda:<env>` when a Conda environment is active
- `venv:<name>` when a Python virtualenv is active (and Conda is not)
- `ssh`, `tmux`, `screen` markers when the session runs in those contexts
- both, separated by `|`, when both are available
- all, separated by `|`, when several are available
**Writing a custom theme file:**

View File

@@ -201,6 +201,10 @@ TERM=xterm-256color
# Include Git dirty marker and upstream drift (+ahead/-behind) in the context.
#PROMPT_SHOW_GIT_STATUS=1
#
# Timeout in seconds for git diff and git rev-list operations.
# If exceeded, the prompt displays git:<branch>? instead of full status.
#PROMPT_GIT_TIMEOUT=2
#
# Show Conda environment name at the end of the top bar when active.
#PROMPT_SHOW_CONDA=1
#

View File

@@ -121,7 +121,7 @@ load_theme()
_lth_line="${_lth_line%$'\r'}" # strip CR
_lth_line="${_lth_line#"${_lth_line%%[![:space:]]*}"}" # ltrim
_lth_line="${_lth_line%"${_lth_line##*[![:space:]]}"}" # rtrim
[[ -z "$_lth_line" || "$_lth_line" == '#'* ]] && continue # blank/comment
[[ -z "$_lth_line" || "$_lth_line" == '#'* ]] && continue # blank/comment
[[ "$_lth_line" == 'export '* ]] && _lth_line="${_lth_line#export }" # strip prefix
if [[ "$_lth_line" != *=* ]]; then
@@ -519,25 +519,56 @@ set_prompt()
branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null) || \
branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
local dirty="" sync=""
local dirty="" sync="" timed_out=0
local _git_timeout="${PROMPT_GIT_TIMEOUT:-2}"
# Build a timeout wrapper if the 'timeout' command is available;
# fall back to direct execution on systems that lack it.
local -a _tw=()
command -v timeout >/dev/null 2>&1 && _tw=(timeout "$_git_timeout")
if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then
if ! git diff --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null || \
! git diff --cached --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null; then
local _ec
# Dirty check — working tree
"${_tw[@]}" git diff --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null
_ec=$?
if [[ $_ec -eq 124 ]]; then
timed_out=1
elif [[ $_ec -ne 0 ]]; then
dirty="*"
else
# Dirty check — index
"${_tw[@]}" git diff --cached --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null
_ec=$?
if [[ $_ec -eq 124 ]]; then
timed_out=1
elif [[ $_ec -ne 0 ]]; then
dirty="*"
fi
fi
local counts ahead behind
counts=$(git rev-list --left-right --count "@{upstream}...HEAD" 2>/dev/null) || counts=""
if [[ "$counts" =~ ^([0-9]+)[[:space:]]+([0-9]+)$ ]]; then
behind="${BASH_REMATCH[1]}"
ahead="${BASH_REMATCH[2]}"
if [[ "$ahead" -gt 0 || "$behind" -gt 0 ]]; then
sync=" +${ahead}/-${behind}"
if [[ $timed_out -eq 0 ]]; then
local counts ahead behind
counts=$("${_tw[@]}" git rev-list --left-right --count "@{upstream}...HEAD" 2>/dev/null)
_ec=$?
if [[ $_ec -eq 124 ]]; then
timed_out=1
elif [[ "$counts" =~ ^([0-9]+)[[:space:]]+([0-9]+)$ ]]; then
behind="${BASH_REMATCH[1]}"
ahead="${BASH_REMATCH[2]}"
if [[ "$ahead" -gt 0 || "$behind" -gt 0 ]]; then
sync=" +${ahead}/-${behind}"
fi
fi
fi
fi
printf "%s" "git:${branch}${dirty}${sync}"
if [[ $timed_out -eq 1 ]]; then
printf "%s" "git:${branch}?"
else
printf "%s" "git:${branch}${dirty}${sync}"
fi
}
local _prompt_conda_env