bash prompt: use bash builtins to find out current branch

__git_ps1() runs the '$(git symbolic-ref HEAD)' command substitution to find out whether we are on a branch and to find out the name of that branch. This imposes the overhead of fork()ing a subshell and fork()+exec()ing a git process. Since HEAD is in most cases a single-line file and the symbolic ref format is quite simple to recognize and parse, read and parse it using only bash builtins, thereby sparing all that fork()+exec() overhead. Don't display the git prompt if reading HEAD fails, because a readable HEAD is required for a git repository. HEAD can also be a symlink symbolic ref (due to 'core.preferSymlinkRefs'), so use bash builtins for reading HEAD only when HEAD is not a symlink. Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>

SZEDER Gábor committed Mar 31, 2011 at 23:41 UTC 3a43c4b5bd19528229ef36b28d648d5ac98f15f1
1 file changed +33 -18
contrib/completion/git-prompt.sh
+33 -18
@@ -355,25 +355,40 @@ __git_ps1 ()
355 r="|BISECTING"
356 fi
357
358 - test -n "$b" ||
359 - b="$(git symbolic-ref HEAD 2>/dev/null)" || {
360 - detached=yes
361 - b="$(
362 - case "${GIT_PS1_DESCRIBE_STYLE-}" in
363 - (contains)
364 - git describe --contains HEAD ;;
365 - (branch)
366 - git describe --contains --all HEAD ;;
367 - (describe)
368 - git describe HEAD ;;
369 - (* | default)
370 - git describe --tags --exact-match HEAD ;;
371 - esac 2>/dev/null)" ||
358 + if [ -n "$b" ]; then
359 + :
360 + elif [ -h "$g/HEAD" ]; then
361 + # symlink symbolic ref
362 + b="$(git symbolic-ref HEAD 2>/dev/null)"
363 + else
364 + local head=""
365 + if ! read head 2>/dev/null <"$g/HEAD"; then
366 + if [ $pcmode = yes ]; then
367 + PS1="$ps1pc_start$ps1pc_end"
368 + fi
369 + return
370 + fi
371 + # is it a symbolic ref?
372 + b="${head#ref: }"
373 + if [ "$head" = "$b" ]; then
374 + detached=yes
375 + b="$(
376 + case "${GIT_PS1_DESCRIBE_STYLE-}" in
377 + (contains)
378 + git describe --contains HEAD ;;
379 + (branch)
380 + git describe --contains --all HEAD ;;
381 + (describe)
382 + git describe HEAD ;;
383 + (* | default)
384 + git describe --tags --exact-match HEAD ;;
385 + esac 2>/dev/null)" ||
386
373 - b="$(git rev-parse --short HEAD 2>/dev/null)..." ||
374 - b="unknown"
375 - b="($b)"
376 - }
387 + b="$(git rev-parse --short HEAD 2>/dev/null)..." ||
388 + b="unknown"
389 + b="($b)"
390 + fi
391 + fi
392 fi
393
394 if [ -n "$step" ] && [ -n "$total" ]; then