aboutsummaryrefslogtreecommitdiff
path: root/bash
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2013-09-21 17:22:21 +1200
committerTom Ryder <tom@sanctum.geek.nz>2013-09-21 17:22:21 +1200
commit4a541b99e644557ff8909f883d4d6cb90a994176 (patch)
tree5705500f5308d25b06b43de1b9a1a7bf5efb0321 /bash
parentRemove subshell call from status print (diff)
downloaddotfiles-4a541b99e644557ff8909f883d4d6cb90a994176.tar.gz
dotfiles-4a541b99e644557ff8909f883d4d6cb90a994176.zip
Complete overhaul of git prompt function
This uses the output of ``git status -z --porcelain'', which was designed for exactly this kind of reason. It avoids excessive program calls, forks, and a few subshells, and is consistently faster on everything I've tried so far.
Diffstat (limited to 'bash')
-rw-r--r--bash/bashrc.d/prompt.bash60
1 files changed, 25 insertions, 35 deletions
diff --git a/bash/bashrc.d/prompt.bash b/bash/bashrc.d/prompt.bash
index f008cf11..f5566323 100644
--- a/bash/bashrc.d/prompt.bash
+++ b/bash/bashrc.d/prompt.bash
@@ -43,65 +43,55 @@ prompt() {
PS1='\$ '
;;
- # Git prompt function
git)
- # Bail if we have no git(1)
+ # Bail if we have no git(1) or if our git status call fails
if ! hash git 2>/dev/null; then
return 1
fi
- # Exit if inside a .git directory
- local gitdir=$(git rev-parse --is-inside-git-dir 2>/dev/null)
- if [[ $gitdir == true ]]; then
+ # Bail if the required git status call fails
+ if ! git status -z --porcelain >/dev/null 2>&1; then
return 1
fi
- # Exit if not inside a working tree
- local worktree=$(git rev-parse --is-inside-work-tree 2>/dev/null)
- if [[ $worktree != true ]]; then
- return 1
- fi
-
- # Read the repository's status to refresh its info; ignore all the
- # output; give up if this fails
- if ! git status >/dev/null 2>&1; then
- return 1
- fi
-
- # Figure out the branch to show for HEAD, whether a symbolic
- # reference or a short SHA-1; chop off any leading path
+ # Attempt to determine git branch
local branch
branch=$(git symbolic-ref --quiet HEAD 2>/dev/null) \
|| branch=$(git rev-parse --short HEAD 2>/dev/null) \
|| branch=unknown
branch=${branch##*/}
- # Start collecting working copy state flags
+ # Safely read status from ``git porcelain''
+ local line ready modified untracked
+ while IFS= read -d $'\0' -r line _; do
+ if [[ $line == [MADRC]* ]]; then
+ ready=1
+ fi
+ if [[ $line == ?[MADRC]* ]]; then
+ modified=1
+ fi
+ if [[ $line == '??'* ]]; then
+ untracked=1
+ fi
+ done < <(git status -z --porcelain 2>/dev/null)
+
+ # Build state array from status output flags
local -a state
-
- # If there are staged changes in the working tree, add a plus sign
- # to the state
- if ! git diff --quiet --ignore-submodules --cached; then
+ if [[ $ready ]]; then
state=("${state[@]}" '+')
fi
-
- # If there are any modified tracked files in the working tree, add
- # an exclamation mark to the state
- if ! git diff-files --quiet --ignore-submodules --; then
+ if [[ $modified ]]; then
state=("${state[@]}" '!')
fi
+ if [[ $untracked ]]; then
+ state=("${state[@]}" '?')
+ fi
- # If there are any stashed changes, add a circumflex to the state
+ # Add another indicator if we have stashed changes
if git rev-parse --verify refs/stash >/dev/null 2>&1; then
state=("${state[@]}" '^')
fi
- # If there are any new unignored files in the working tree, add a
- # question mark to the state
- if [[ $(git ls-files --others --exclude-standard) ]]; then
- state=("${state[@]}" '?')
- fi
-
# Print the status in brackets with a git: prefix
local IFS=
printf '(git:%s%s)' "${branch:-unknown}" "${state[*]}"