Skip to content

Commit

Permalink
Merge branch 'sg/bash-prompt'
Browse files Browse the repository at this point in the history
* sg/bash-prompt:
  bash prompt: mention that PROMPT_COMMAND mode is faster
  bash prompt: avoid command substitution when finalizing gitstring
  bash prompt: avoid command substitution when checking for untracked files
  bash prompt: use bash builtins to check stash state
  bash prompt: use bash builtins to check for unborn branch for dirty state
  bash prompt: combine 'git rev-parse' for detached head
  bash prompt: combine 'git rev-parse' executions in the main code path
  bash prompt: use bash builtins to find out current branch
  bash prompt: use bash builtins to find out rebase state
  bash prompt: run 'git rev-parse --git-dir' directly instead of __gitdir()
  bash prompt: return early from __git_ps1() when not in a git repository
  bash prompt: print unique detached HEAD abbreviated object name
  bash prompt: add a test for symbolic link symbolic refs
  completion, bash prompt: move __gitdir() tests to completion test suite
  bash prompt: use 'write_script' helper in interactive rebase test
  bash prompt: fix redirection coding style in tests
  • Loading branch information
Junio C Hamano committed Jul 1, 2013
2 parents 0d07e98 + a694258 commit 6935020
Show file tree
Hide file tree
Showing 4 changed files with 367 additions and 333 deletions.
2 changes: 0 additions & 2 deletions contrib/completion/git-completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ esac
# returns location of .git repo
__gitdir ()
{
# Note: this function is duplicated in git-prompt.sh
# When updating it, make sure you update the other one to match.
if [ -z "${1-}" ]; then
if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
Expand Down
241 changes: 127 additions & 114 deletions contrib/completion/git-prompt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
# the optional argument will be used as format string.
# 3b) Alternatively, if you are using bash, __git_ps1 can be
# used for PROMPT_COMMAND with two parameters, <pre> and
# <post>, which are strings you would put in $PS1 before
# and after the status string generated by the git-prompt
# machinery. e.g.
# 3b) Alternatively, for a slighly faster prompt, if you are
# using bash, __git_ps1 can be used for PROMPT_COMMAND
# with two parameters, <pre> and <post>, which are strings
# you would put in $PS1 before and after the status string
# generated by the git-prompt machinery. e.g.
# Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
# ZSH: precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
# will show username, at-sign, host, colon, cwd, then
Expand Down Expand Up @@ -80,30 +80,6 @@
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb".

# __gitdir accepts 0 or 1 arguments (i.e., location)
# returns location of .git repo
__gitdir ()
{
# Note: this function is duplicated in git-completion.bash
# When updating it, make sure you update the other one to match.
if [ -z "${1-}" ]; then
if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
elif [ -n "${GIT_DIR-}" ]; then
test -d "${GIT_DIR-}" || return 1
echo "$GIT_DIR"
elif [ -d .git ]; then
echo .git
else
git rev-parse --git-dir 2>/dev/null
fi
elif [ -d "$1/.git" ]; then
echo "$1/.git"
else
echo "$1"
fi
}

# stores the divergence from upstream in $p
# used by GIT_PS1_SHOWUPSTREAM
__git_ps1_show_upstream ()
Expand Down Expand Up @@ -335,50 +311,83 @@ __git_ps1 ()
;;
esac

local g="$(__gitdir)"
if [ -z "$g" ]; then
local repo_info rev_parse_exit_code
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
--is-bare-repository --is-inside-work-tree \
--short HEAD 2>/dev/null)"
rev_parse_exit_code="$?"

if [ -z "$repo_info" ]; then
if [ $pcmode = yes ]; then
#In PC mode PS1 always needs to be set
PS1="$ps1pc_start$ps1pc_end"
fi
return
fi

local short_sha
if [ "$rev_parse_exit_code" = "0" ]; then
short_sha="${repo_info##*$'\n'}"
repo_info="${repo_info%$'\n'*}"
fi
local inside_worktree="${repo_info##*$'\n'}"
repo_info="${repo_info%$'\n'*}"
local bare_repo="${repo_info##*$'\n'}"
repo_info="${repo_info%$'\n'*}"
local inside_gitdir="${repo_info##*$'\n'}"
local g="${repo_info%$'\n'*}"

local r=""
local b=""
local step=""
local total=""
if [ -d "$g/rebase-merge" ]; then
read b 2>/dev/null <"$g/rebase-merge/head-name"
read step 2>/dev/null <"$g/rebase-merge/msgnum"
read total 2>/dev/null <"$g/rebase-merge/end"
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
else
r="|REBASE-m"
fi
else
local r=""
local b=""
local step=""
local total=""
if [ -d "$g/rebase-merge" ]; then
b="$(cat "$g/rebase-merge/head-name" 2>/dev/null)"
step=$(cat "$g/rebase-merge/msgnum" 2>/dev/null)
total=$(cat "$g/rebase-merge/end" 2>/dev/null)
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
if [ -d "$g/rebase-apply" ]; then
read step 2>/dev/null <"$g/rebase-apply/next"
read total 2>/dev/null <"$g/rebase-apply/last"
if [ -f "$g/rebase-apply/rebasing" ]; then
read b 2>/dev/null <"$g/rebase-apply/head-name"
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
else
r="|REBASE-m"
r="|AM/REBASE"
fi
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
r="|CHERRY-PICKING"
elif [ -f "$g/REVERT_HEAD" ]; then
r="|REVERTING"
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi

if [ -n "$b" ]; then
:
elif [ -h "$g/HEAD" ]; then
# symlink symbolic ref
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
if [ -d "$g/rebase-apply" ]; then
step=$(cat "$g/rebase-apply/next" 2>/dev/null)
total=$(cat "$g/rebase-apply/last" 2>/dev/null)
if [ -f "$g/rebase-apply/rebasing" ]; then
b="$(cat "$g/rebase-apply/head-name" 2>/dev/null)"
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
else
r="|AM/REBASE"
local head=""
if ! read head 2>/dev/null <"$g/HEAD"; then
if [ $pcmode = yes ]; then
PS1="$ps1pc_start$ps1pc_end"
fi
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
r="|CHERRY-PICKING"
elif [ -f "$g/REVERT_HEAD" ]; then
r="|REVERTING"
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
return
fi

test -n "$b" ||
b="$(git symbolic-ref HEAD 2>/dev/null)" || {
# is it a symbolic ref?
b="${head#ref: }"
if [ "$head" = "$b" ]; then
detached=yes
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
Expand All @@ -392,70 +401,74 @@ __git_ps1 ()
git describe --tags --exact-match HEAD ;;
esac 2>/dev/null)" ||

b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
b="unknown"
b="$short_sha..."
b="($b)"
}
fi
fi
fi

if [ -n "$step" ] && [ -n "$total" ]; then
r="$r $step/$total"
fi
if [ -n "$step" ] && [ -n "$total" ]; then
r="$r $step/$total"
fi

local w=""
local i=""
local s=""
local u=""
local c=""
local p=""
local w=""
local i=""
local s=""
local u=""
local c=""
local p=""

if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
if [ "true" = "$inside_gitdir" ]; then
if [ "true" = "$bare_repo" ]; then
c="BARE:"
else
b="GIT_DIR!"
fi
elif [ "true" = "$inside_worktree" ]; then
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
[ "$(git config --bool bash.showDirtyState)" != "false" ]
then
git diff --no-ext-diff --quiet --exit-code || w="*"
if [ -n "$short_sha" ]; then
git diff-index --cached --quiet HEAD -- || i="+"
else
b="GIT_DIR!"
fi
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
[ "$(git config --bool bash.showDirtyState)" != "false" ]
then
git diff --no-ext-diff --quiet --exit-code || w="*"
if git rev-parse --quiet --verify HEAD >/dev/null; then
git diff-index --cached --quiet HEAD -- || i="+"
else
i="#"
fi
fi
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
i="#"
fi
fi
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
[ -r "$g/refs/stash" ]; then
s="$"
fi

if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
[ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
[ -n "$(git ls-files --others --exclude-standard)" ]
then
u="%${ZSH_VERSION+%}"
fi
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
[ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
git ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null
then
u="%${ZSH_VERSION+%}"
fi

if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
__git_ps1_show_upstream
fi
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
__git_ps1_show_upstream
fi
fi

local z="${GIT_PS1_STATESEPARATOR-" "}"
local f="$w$i$s$u"
if [ $pcmode = yes ]; then
local gitstring=
if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
__git_ps1_colorize_gitstring
else
gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
fi
local z="${GIT_PS1_STATESEPARATOR-" "}"
local f="$w$i$s$u"
if [ $pcmode = yes ]; then
local gitstring=
if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
__git_ps1_colorize_gitstring
else
gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
fi
if [[ -n ${ZSH_VERSION-} ]]; then
gitstring=$(printf -- "$printf_format" "$gitstring")
PS1="$ps1pc_start$gitstring$ps1pc_end"
else
# NO color option unless in PROMPT_COMMAND mode
printf -- "$printf_format" "$c${b##refs/heads/}${f:+$z$f}$r$p"
printf -v gitstring -- "$printf_format" "$gitstring"
fi
PS1="$ps1pc_start$gitstring$ps1pc_end"
else
# NO color option unless in PROMPT_COMMAND mode
printf -- "$printf_format" "$c${b##refs/heads/}${f:+$z$f}$r$p"
fi
}
Loading

0 comments on commit 6935020

Please sign in to comment.