Created a git library to easily create a prompt

__git_ps1 (as in the git contrib file) is available through the newly added library.
This library allows to do more elaborated prompts based on :
 - Current directory type
 - Current action running in the repository (merge/rebase/...)
 - Current branch (with relative names or long/short sha1s)
 - Current index state (file added to working tree/index, etc.)
 - Status compared to upstream (git only)
This commit is contained in:
Colin Hebert 2011-06-18 23:57:09 +01:00
commit a434414cd0

View file

@ -1,3 +1,253 @@
GIT_PROMPT_BRANCH_STYLE=""
GIT_PROMPT_STASH_STATE="y"
GIT_PROMPT_SHA="short"
function __git_ps1() {
local current_dir_status current_repo_status current_branch
local current_index_state current_upstream_status
local r b w i s u c p f
current_dir_status="$(_git_current_dir_status)"
if [ "$current_dir_status" = 'not-git' ]; then
return
fi
current_repo_status="$(_git_current_repo_status)"
current_branch="$(_git_current_branch "$current_repo_status")"
r="$(case "${current_repo_status}" in
('rebase-interactive')
echo '|REBASE-i' ;;
('rebase-merge')
echo '|REBASE-m' ;;
('rebase')
echo '|REBASE' ;;
('am')
echo '|AM' ;;
('am-rebase')
echo '|AM/REBASE' ;;
('merge')
echo '|MERGING' ;;
('cherry-pick')
echo '|CHERRY-PICKING' ;;
('bisect')
echo '|BISECTING' ;;
esac)"
b="$current_branch"
if [ "$current_dir_status" = 'bare' ]; then
c="BARE:"
elif [ "$current_dir_status" = 'git-dir' ]; then
b="GIT_DIR!"
elif [ "$current_dir_status" = 'work-tree' ]; then
current_index_state="$(_git_current_index_state)"
if [[ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]]; then
w="$(case "${current_index_state}" in
(*'wtmodified'* | *'wtdeleted'*)
echo '*' ;;
esac)"
i="$(case "${current_index_state}" in
(*'imodified'* | *'iadded'* | *'ideleted'* | *'irenamed'* | *'icopied'*)
echo '+' ;;
esac)"
fi
if [[ -n "${GIT_PS1_SHOWSTASHSTATE-}" && "$current_index_state" == *'stashed'* ]]; then
s='$'
fi
if [[ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" && "$current_index_state" == *'untracked'* ]]; then
u='%%'
fi
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
current_upstream_status="$(_git_current_upstream_status)"
p="$(case "$current_upstream_status" in
('equal-upstream')
echo '=' ;;
('ahead-upstream')
echo '>' ;;
('behind-upstream')
echo '<' ;;
('diverged-from-upstream')
echo '<>' ;;
esac)"
fi
fi
f="$w$i$s$u"
printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
}
function git_prompt_info() {
#Todo rewrite git_prompt_info
}
function _git_current_git_dir() {
echo "$(__git_safe rev-parse --git-dir)"
}
function _git_current_dir_status() {
local dir_status
if [ -z "$(__git_safe rev-parse --git-dir)" ]; then
dir_status='not-git'
elif [ "$(__git_safe rev-parse --is-bare-repository)" = 'true' ]; then
dir_status='bare'
elif [ "$(__git_safe rev-parse --is-inside-git-dir)" = 'true' ]; then
dir_status='git-dir'
elif [ "$(__git_safe rev-parse --is-inside-work-tree)" = 'true' ]; then
dir_status='work-tree'
else
dir_status='unkown'
fi
echo $dir_status
}
function _git_current_repo_status() {
local gitRepository=$(_git_current_git_dir)
local repo_status
if [ -f "$gitRepository/rebase-merge/interactive" ]; then
repo_status='rebase-interactive'
elif [ -d "$gitRepository/rebase-merge" ]; then
repo_status='rebase-merge'
elif [ -d "$gitRepository/rebase-apply" ]; then
if [ -f "$gitRepository/rebase-apply/rebasing" ]; then
repo_status='rebase'
elif [ -f "$gitRepository/rebase-apply/applying" ]; then
repo_status='am'
else
repo_status='am-rebase'
fi
elif [ -f "$gitRepository/MERGE_HEAD" ]; then
repo_status='merge'
elif [ -f "$gitRepository/CHERRY_PICK_HEAD" ]; then
repo_status='cherry-pick'
elif [ -f "$gitRepository/BISECT_LOG" ]; then
repo_status='bisect'
else
repo_status='normal'
fi
echo $repo_status
}
function _git_current_branch() {
local branch
local repo_status
if [ -n "$1" ]; then
repo_status="$1"
else
repo_status="$(_git_current_repo_status)"
fi
if [[ "$repo_status" = 'rebase-interactive' || "$repo_status" = 'rebase-merge' ]]; then
branch="$(cat "$(_git_current_git_dir)/rebase-merge/head-name")"
else
branch="$(__git_safe symbolic-ref HEAD)"
if [ -z $branch ]; then
if [ "$GIT_PROMPT_BRANCH_STYLE" = 'contains' ]; then
branch="$(__git_safe describe --contains HEAD)"
elif [ "$GIT_PROMPT_BRANCH_STYLE" = 'branch' ]; then
branch="$(__git_safe describe --contains --all HEAD)"
elif [ "$GIT_PROMPT_BRANCH_STYLE" = 'describe' ]; then
branch="$(__git_safe describe HEAD)"
else
branch="$(__git_safe describe --tags --exact-match HEAD)"
fi
fi
if [ -z $branch ]; then
if [ "$GIT_PROMPT_SHA" = 'long' ]; then
branch="$(__git_safe rev-parse HEAD)"
else
branch="$(__git_safe rev-parse --short HEAD)..."
fi
fi
if [[ -z $branch || $branch = '...' ]]; then
branch='unknow'
fi
fi
echo $branch
}
function _git_current_index_state(){
local index_state=''
local index_status="$(__git_safe status --porcelain)"
#based on git-status 'Short Format' man page
if [ -n "$(__git_grep_status "$index_status" 'M.')" ]; then
index_state="imodified ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" 'A[ MD]')" ]; then
index_state="iadded ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" 'D[ M]')" ]; then
index_state="ideleted ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" 'R.')" ]; then
index_state="irenamed ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" 'C.')" ]; then
index_state="icopied ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" '.M')" ]; then
index_state="wtmodified ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" '[ MARC]D')" ]; then
index_state="wtdeleted ${index_state}"
fi
if [ -n "$(__git_grep_status "$index_status" '??')" ]; then
index_state="untracked ${index_state}"
fi
if [[ -n "${GIT_PROMPT_STASH_STATE-}" && -n "$(__git_safe stash list)" ]]; then
index_state="stashed ${index_state}"
fi
echo $index_state
}
function _git_current_upstream_status() {
#Todo handle svn remotes
local upstream_status
local upstream='@{upstream}'
local differences_count="$(__git_safe rev-list --count --left-right "$upstream"...HEAD)"
case "$differences_count" in
'') # no upstream
upstream_status='no-upstream' ;;
'0 0') # equal to upstream
upstream_status='equal-upstream' ;;
'0 '*) # ahead of upstream
upstream_status='ahead-upstream' ;;
*' 0') # behind upstream
upstream_status='behind-upstream' ;;
*) # diverged from upstream
upstream_status='diverged-from-upstream' ;;
esac
echo $upstream_status
}
function __git_safe(){
echo "$(git $* 2>/dev/null)"
}
function __git_grep_status(){
echo "$(echo "$1" | grep "^$2 ")"
}
# get the name of the branch we are on # get the name of the branch we are on
function git_prompt_info() { function git_prompt_info() {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return ref=$(git symbolic-ref HEAD 2> /dev/null) || return