diff --git a/lib/git.zsh b/lib/git.zsh index ce4de5598..3572488bc 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -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 function git_prompt_info() { ref=$(git symbolic-ref HEAD 2> /dev/null) || return