Skip to content

Commit

Permalink
Set a timeout on git commands
Browse files Browse the repository at this point in the history
The calculate of git_summary_status can be extremely expensive for large
repos. This results in the shell becoming unresponsive.

We now set a timeout of 0.2 seconds to make sure we always have
a responsive shell.

Fixes ohmybash#172
  • Loading branch information
Erwin Jansen committed Aug 28, 2020
1 parent c37486a commit da1ef1a
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions themes/base.theme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ SCM_GIT_SHOW_CURRENT_USER=${SCM_GIT_SHOW_CURRENT_USER:=false}
SCM_GIT_SHOW_MINIMAL_INFO=${SCM_GIT_SHOW_MINIMAL_INFO:=false}

SCM_GIT='git'

SCM_GIT_CHAR='±'
SCM_GIT_DETACHED_CHAR=''
SCM_GIT_AHEAD_CHAR=""
SCM_GIT_BEHIND_CHAR=""
SCM_GIT_UNTRACKED_CHAR="?:"
SCM_GIT_UNSTAGED_CHAR="U:"
SCM_GIT_STAGED_CHAR="S:"
SCM_GIT_TIMEOUT="0.2"

SCM_HG='hg'
SCM_HG_CHAR=''
Expand All @@ -65,6 +67,23 @@ RBENV_THEME_PROMPT_SUFFIX='|'
RBFU_THEME_PROMPT_PREFIX=' |'
RBFU_THEME_PROMPT_SUFFIX='|'

function run_with_timeout() {
# Runs the given command with the given timeout
# $1 Timeout in seconds
# $@ Command to be executed.
local TIME=$1
shift
local CMD=$@
local TIMEOUT=
if which timeout &> /dev/null; then
TIMEOUT=timeout
elif which gtimeout &> /dev/null; then
TIMEOUT=gtimeout
fi

$TIMEOUT ${TIME} ${CMD}
}

function scm {
if [[ "$SCM_CHECK" = false ]]; then SCM=$SCM_NONE
elif [[ -f .git/HEAD ]]; then SCM=$SCM_GIT
Expand Down Expand Up @@ -150,7 +169,7 @@ function git_prompt_minimal_info {

# Get the status
[[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && git_status_flags+='-untracked-files=no'
status=$(command git status ${git_status_flags} 2> /dev/null | tail -n1)
status=$(run_with_timeout $SCM_GIT_TIMEOUT git status ${git_status_flags} 2> /dev/null | tail -n1)

if [[ -n ${status} ]]; then
SCM_DIRTY=1
Expand Down Expand Up @@ -200,8 +219,8 @@ function git_prompt_vars {
SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN}
if [[ "$(git config --get bash-it.hide-status)" != "1" ]]; then
[[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno'
local status_lines=$((git status --porcelain ${git_status_flags} -b 2> /dev/null ||
git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary)
local status_lines=$((run_with_timeout $SCM_GIT_TIMEOUT git status --porcelain ${git_status_flags} -b 2> /dev/null ||
run_with_timeout $SCM_GIT_TIMEOUT git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary)
local status=$(awk 'NR==1' <<< "$status_lines")
local counts=$(awk 'NR==2' <<< "$status_lines")
IFS=$'\t' read untracked_count unstaged_count staged_count <<< "$counts"
Expand Down

0 comments on commit da1ef1a

Please sign in to comment.