ohmyzsh/lib/git.zsh
Colin Hebert a434414cd0 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)
2011-06-19 17:10:51 +01:00

312 lines
8.5 KiB
Bash

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
function git_prompt_info() {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_SUFFIX"
}
# Checks if working tree is dirty
parse_git_dirty() {
if [[ -n $(git status -s 2> /dev/null) ]]; then
echo "$ZSH_THEME_GIT_PROMPT_DIRTY"
else
echo "$ZSH_THEME_GIT_PROMPT_CLEAN"
fi
}
# Checks if there are commits ahead from remote
function git_prompt_ahead() {
if $(echo "$(git log origin/$(current_branch)..HEAD 2> /dev/null)" | grep '^commit' &> /dev/null); then
echo "$ZSH_THEME_GIT_PROMPT_AHEAD"
fi
}
# Formats prompt string for current git commit short SHA
function git_prompt_short_sha() {
SHA=$(git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}
# Formats prompt string for current git commit long SHA
function git_prompt_long_sha() {
SHA=$(git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}
# Get the status of the working tree
git_prompt_status() {
INDEX=$(git status --porcelain 2> /dev/null)
STATUS=""
if $(echo "$INDEX" | grep '^?? ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_UNTRACKED$STATUS"
fi
if $(echo "$INDEX" | grep '^A ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
elif $(echo "$INDEX" | grep '^M ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
fi
if $(echo "$INDEX" | grep '^ M ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
elif $(echo "$INDEX" | grep '^AM ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
elif $(echo "$INDEX" | grep '^ T ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
fi
if $(echo "$INDEX" | grep '^R ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_RENAMED$STATUS"
fi
if $(echo "$INDEX" | grep '^D ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
fi
if $(echo "$INDEX" | grep '^UU ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_UNMERGED$STATUS"
fi
echo $STATUS
}