Bash 和 Zsh 中 Prompt 显示 Git 分支
Bash 和 Zsh 环境 Prompt 显示 Git 分支
·
在 Shell 中显示 Git 分支对于提高效率非常有帮助,毕竟 Bug 不会在你准备好了才出现,在 Branch 之间切来切去已经习以为常,不喜欢折腾的话可以直接 Oh My Zsh,简单易用不浪费生命。但是对于一些极端环境,例如小容器内部,或者没有太多权限的服务环境下,Oh My Zsh 就显得不适用了,所以我们来探索一个 DIY 版本。
Bash/Zsh 环境修改 Prompt 的原理就是修改 PS1
环境变量。原理很简单,实现也并不复杂,毕竟 git describe
git rev-parse
git show-ref
git branch
git status
之类的二级命令累加即可实现,但是如果使用 time git status
执行一下就会发现,执行的时间是不可控的,尤其是在大的 Repo 里面,执行时间往往是百毫秒级的,这样对于使用体验来说是极差的,毕竟执行一次回车,要等待大于人眼反映速度的时间就会感到明显的卡顿,所以在设计时首先需要考虑的因素是执行时间。
对于执行时间的优化可以通过下面这种方法来解决。每个 Repo 都有一个 .git/HEAD
文件用来保存当前 HEAD 所在的 commit 的 SHA1 值,只要我们每次执行时首先判断这个 SHA1 值是否变化才决定是否进行 branch 重新计算即可。经实验执行时间可以控制在 10ms 以内。
GIT_NAME_TITLE=''
GIT_NAME_CONTENT=''
GIT_NAME_LEFT=''
GIT_NAME_RIGHT=''
GIT_NAME_HEAD=''
function git_branch_internal()
{
local dir="."
until [ "${dir}" -ef / ]; do
if [ -f "${dir}/.git/HEAD" ]; then
local head=$(< "${dir}/.git/HEAD")
if [[ ${head} == ${GIT_NAME_HEAD} ]]; then
return
fi
GIT_NAME_HEAD=${head}
if [[ $head =~ ^ref\:\ refs\/heads\/* ]]; then
GIT_NAME_TITLE="branch"
GIT_NAME_CONTENT="${head#*/*/}"
else
local describe=$(git describe --tags --abbrev=7 2> /dev/null)
if [ -n "${describe}" ]; then
GIT_NAME_TITLE="tag"
GIT_NAME_CONTENT=${describe}
else
GIT_NAME_TITLE="commit"
GIT_NAME_CONTENT=${head:0:7}
fi
fi
GIT_NAME_LEFT=":["
GIT_NAME_RIGHT="]"
return
fi
dir="../${dir}"
done
GIT_NAME_TITLE=''
GIT_NAME_CONTENT=''
GIT_NAME_LEFT=''
GIT_NAME_RIGHT=''
GIT_NAME_HEAD=''
}
# Git branch perception
function git_zsh_precmd()
{
git_branch_internal
PS1="${PS1_BAK}%{$fg_bold[blue]%}${GIT_NAME_TITLE}${GIT_NAME_LEFT}%{$fg_bold[red]%}${GIT_NAME_CONTENT}%{$fg_bold[blue]%}${GIT_NAME_RIGHT}%% %{$reset_color%}"
}
# color for PS1
black=$'\[\e[1;30m\]'
red=$'\[\e[1;31m\]'
green=$'\[\e[1;32m\]'
yellow=$'\[\e[1;33m\]'
blue=$'\[\e[1;34m\]'
magenta=$'\[\e[1;35m\]'
cyan=$'\[\e[1;36m\]'
white=$'\[\e[1;37m\]'
normal=$'\[\e[m\]'
# Git prompt for branch infomation
function git_prompt()
{
if [ "${PS1_BAK-NODEFINE}" = "NODEFINE" ] ; then
PS1_BAK=${PS1-}
if [[ ${SHELL} =~ .*bash$ ]]; then
PROMPT_COMMAND_BAK=${PROMPT_COMMAND-}
PROMPT_COMMAND="git_branch_internal;${PROMPT_COMMAND-}"
PS1="$PS1$blue\$GIT_NAME_TITLE\$GIT_NAME_LEFT$red\$GIT_NAME_CONTENT$blue\$GIT_NAME_RIGHT\$ $normal"
elif [[ ${SHELL} =~ .*zsh$ ]]; then
autoload -U colors && colors
precmd_functions=(git_zsh_precmd)
fi
else
if [[ ${SHELL} =~ .*bash$ ]]; then
PROMPT_COMMAND=${PROMPT_COMMAND_BAK-}
unset PROMPT_COMMAND_BAK
elif [[ ${SHELL} =~ .*zsh$ ]]; then
unset precmd_functions
fi
PS1=${PS1_BAK-}
unset PS1_BAK
GIT_NAME_HEAD=''
fi
}
参考文档
更多推荐
已为社区贡献3条内容
所有评论(0)