I am using this function in Bash
function parse_git_branch {
git_status="$(git status 2> /dev/null)"
pattern="^# On branch ([^${IFS}]*)"
if [[ ! ${git_status}} =~ "working directory clean" ]]; then
state="*"
fi
# add an else if or two here if you want to get more specific
if [[ $开发者_开发问答{git_status} =~ ${pattern} ]]; then
branch=${BASH_REMATCH[1]}
echo "(${branch}${state})"
fi
}
but I'm determined to use zsh. While I can use this perfectly as a shell script (even without a shebang) in my .zshrc the error is a parse error on this line if [[ ! ${git_status}}
...
What do I need to do to get it ready for zshell?
Edit: The "actual error" I'm getting is " parse error near }
and it refers to the line with the strange double }}
, which works on Bash.
Edit: Here's the final code, just for fun:
parse_git_branch() {
git_status="$(git status 2> /dev/null)"
pattern="^# On branch ([^[:space:]]*)"
if [[ ! ${git_status} =~ "working directory clean" ]]; then
state="*"
fi
if [[ ${git_status} =~ ${pattern} ]]; then
branch=${match[1]}
echo "(${branch}${state})"
fi
}
setopt PROMPT_SUBST
PROMPT='$PR_GREEN%n@$PR_GREEN%m%u$PR_NO_COLOR:$PR_BLUE%2c$PR_NO_COLOR%(!.#.$)'
RPROMPT='$PR_GREEN$(parse_git_branch)$PR_NO_COLOR'
Thanks to everybody for your patience and help.
Edit: The best answer has schooled us all: git status
is porcelain (UI). Good scripting goes against GIT plumbing. Here's the final function:
# The latest version of Chris' function below
PROMPT='$PR_GREEN%n@$PR_GREEN%m%u$PR_NO_COLOR:$PR_BLUE%2c$PR_NO_COLOR%(!.#.$)'
RPROMPT='$PR_GREEN$(parse_git_branch)$PR_NO_COLOR'
Note that only the prompt is zsh-specific. In Bash it would be your prompt plus "\$(parse_git_branch)"
.
This might be slower (more calls to GIT, but that's an empirical question) but it won't be broken by changes in GIT (they don't change the plumbing). And that is very important for a good script moving forward.
You should really use Git “plumbing” commands to extract the info you want. The output from the “porcelain” commands (e.g.git status
) may change over time, but the behavior of the “plumbing” commands is much more stable.
With the porcelain interfaces, it can also be done without “bashisms” or “zshisms” (i.e. the =~
matching operator):
parse_git_branch() {
in_wd="$(git rev-parse --is-inside-work-tree 2>/dev/null)" || return
test "$in_wd" = true || return
state=''
git update-index --refresh -q >/dev/null # avoid false positives with diff-index
if git rev-parse --verify HEAD >/dev/null 2>&1; then
git diff-index HEAD --quiet 2>/dev/null || state='*'
else
state='#'
fi
(
d="$(git rev-parse --show-cdup)" &&
cd "$d" &&
test -z "$(git ls-files --others --exclude-standard .)"
) >/dev/null 2>&1 || state="${state}+"
branch="$(git symbolic-ref HEAD 2>/dev/null)"
test -z "$branch" && branch='<detached-HEAD>'
echo "${branch#refs/heads/}${state}"
}
Integrating the output into the prompt is still shell specific (i.e. escape or quote the $
(for both bash and zsh) and set PROMPT_SUBST (for zsh)).
Get rid of the extra }
? ${git_status}}
should be ${git_status}
.
Once the extra }
is removed, the only potential issue that I see is the use of ${BASH_REMATCH[1]}
. You can use that in zsh, but it requires enabling the option to do so. As zsh docs on conditional expressions show, you would need to use something like
if [[ ${git_status} =~ ${pattern} ]]; then
branch=${match[1]}
echo "(${branch}${state})"
fi
You can use the array match
instead of $BASH_REMATCH
. You can also escape the extra closing curly brace.
Untested:
function parse_git_branch {
git_status="$(git status 2> /dev/null)"
pattern="^# On branch ([^${IFS}]*)"
if [[ ! ${git_status}\} =~ "working directory clean" ]]; then
state="*"
fi
# add an else if or two here if you want to get more specific
if [[ ${git_status} =~ ${pattern} ]]; then
branch=${match[1]}
echo "(${branch}${state})"
fi
}
Give that a try and see if it helps.
If you don't want to learn zsh, I'd suggest you to use another language, like Python, for that kind of parsing.
Check out the git status Python parser and the zsh-git-prompt project on github to see how to get a nice zsh
prompt for git.
If you are getting error failed to compile regex: illegal byte sequence
then remove NULL from IFS. (Replace ${IFS}
with ${IFS//$'\0'/}
).
May be this zsh Git repository will contain Tests which can give you some clue:
- A01grammar.ztst
- A07control.ztst
Just in case anyone is interested to see an alternative solution to the git-prompt functionality, I have posted this script at github.com but to make it easier, you can get it from here.
It works great for me, hope it does the same to you.
## Setting Prompt Colour(s):
invColor="$(tput rev)"; ## tput rev - Inverse
resColor="$(tput sgr0)"; ## tput sgr0 - Reset
## Custom Prompt Colour(s):
_BlackBG="$(tput setab 0)";
bGreenFG="$(tput bold; tput setaf 2)";
bMagentaFG="$(tout bold; tput setaf 5)";
bRedFG="$(tput bold; tput setaf 1)";
bBlueFG="$(tput bold; tput setaf 4)";
bCyanFG="$(tput bold; tput setaf 6)";
bWhiteFG="$(tput bold; tput setaf 7)";
## Define Enclosing-character(s):
_Bracket="${resColor}${_BlackBG}${bWhiteFG}";
oBracket="${_Bracket}["; cBracket="${_Bracket}]${resColor}";
## Bold-Foreground Color(s):
## tput bold - Bold
function git_branch () {
# git_branch() { git name-rev HEAD 2> /dev/null | sed 's#HEAD\ \(.*\)#git::\1#'; }
git branch --no-color 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/git::\1/';
return 0;
}
## Version Control System - Active Working Copy:
function get_branch () {
xBranch="`git_branch`";
if [[ "${xBranch}" =~ "git::master" ]]; then
xBranch="git::${bWhiteFG}master";
else xBranch="`echo ${xBranch}|sed -e 's/git:://g'`";
xBranch="branch::${bGreenFG}${xBranch}";
fi
if git rev-parse --git-dir >/dev/null 2>&1; then
_pVCS="";
if git diff --quiet 2>/dev/null >&2; then
if [[ "${xBranch}" =~ "git::" ]]; then
_pVCS="${bGreenFG}${xBranch}";
else _pVCS="${bMagentaFG}${xBranch}";
fi
else _pVCS="${bRedFG}${xBranch}";
fi
else return 0;
fi
if [[ "${_pVCS}" =~ "no branch" ]]; then
xTAG="`git tags|awk '{print $3}'|sed -e 's/[,;)]//g'`";
_pVCS="${bBlueFG}tag::${bCyanFG}${xTAG}";
fi
## Output Git Active-Repo ID:
if [[ "${_pVCS}" =~ [::] ]]; then
echo -ne "${oBracket}${_BlackBG}${_pVCS}${cBracket}";
fi
# return 0;
}
Usage:
declare PS1='\[\033[01;36m\]\u\[\033[01;31m\]@\[\033[01;32m\]\h\[\033[00m\]:\[\033[01;33m\]\w $(get_branch) \[\033[01;31m\]${XPT}\[\033[00m\] '
精彩评论