Skip to content

Instantly share code, notes, and snippets.

@hilbix
Last active August 6, 2023 17:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hilbix/2bd39b26280ad7d99712 to your computer and use it in GitHub Desktop.
Save hilbix/2bd39b26280ad7d99712 to your computer and use it in GitHub Desktop.
Timeout __git_ps1 on slow network shares

Add following to your .bashrc:

__git_ps1() { setsid -w /bin/bash -c 'sleep 1 & . /usr/lib/git-core/git-sh-prompt && __git_ps1 "$@" & wait -n; p=$(/usr/bin/ps --no-headers -opgrp $$) && [ $$ = ${p:-x} ] && /usr/bin/kill -9 0; echo "PGRP mismatch $$ $p" >&2' bash "$@"; }

1s usually is enough for local files which are in cache on modern machines, but does not delays the shell prompt too much in case network share need a bit longer.

Note: Due to timeout killing git this may leave .lock-files in your .git directory, which is a bit annoying, as git bails out if it sees such .lock when altering a .git repo. However git tells the lockfile positions and you then can(must) manually rm them. You can improve this by setting GIT_PS1_xxxx variables such, that git needs no locking when evaluating the $PS1. However I am not completely sure which options causes this issue or not. YMMV.

What it does:

  • setsid -w /bin/bash -c 'SCRIPT' bash "$@" runs SCRIPT in a new process group
  • sleep 1 & sets the timeout
  • . /usr/lib/git-core/git-sh-prompt && __git_ps1 "$@" & runs the git prompt in parallel
    • /usr/lib/git-core/git-sh-prompt is for Ubuntu 22.04, change it if needed
  • wait -n; waits for either the sleep or __git_ps1 to return
    • The first one wins
  • p=$(/usr/bin/ps --no-headers -opgrp $$) && [ $$ = ${p:-x} ] && is just a safeguard to check setsid worked and we are really a process group leader
    • $$ works here correctly, as we are within single quotes
  • kill -9 0 unconditionally kills the entire process group
    • all git that may still execute
    • including the /bin/bash
  • echo "PGRP mismatch $$ $p" >&2' is never reached
    • This informs you that either setsid is a fake
    • or something else (kill?) did not work as expected

The safeguard protects against the case that setsid does not work as advertised. Without your current shell might get killed, which would make it impossible to spawn an interactive shell.

@hilbix
Copy link
Author

hilbix commented Aug 6, 2023

Updated my SO answer to include this, too:

__git_ps1() { setsid -w /bin/bash -c 'sleep 1 & . /usr/lib/git-core/git-sh-prompt && __git_ps1 "$@" & wait -n; p=$(/usr/bin/ps --no-headers -opgrp $$) && [ $$ = ${p:-x} ] && /usr/bin/kill -9 0; echo "PGRP mismatch $$ $p" >&2' bash "$@"; }

FTR before it looked like

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; r=$?; kill -9 `jobs -p`; exit $r; ) }
eval "__orig$(declare -f __git_ps1)" && __git_ps1() { ( git() { _timeout 0.3 /usr/bin/git "$@"; }; _timeout 0.3 __orig__git_ps1 "$@"; ) }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment