将parse_git_branch函数从bash转换为zsh(用于提示)

时间:2010-05-17 15:32:56

标签: git bash zsh

我在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
}

但我决定使用zsh。虽然我可以在我的.zshrc中完美地使用它作为shell脚本(即使没有shebang),但错误是此行if [[ ! ${git_status}}上的解析错误...

我需要做些什么才能为zshell做好准备?

编辑:我收到的“实际错误”是" parse error near },它指的是带有奇怪的双}}的行,它适用于Bash。

编辑:这是最终的代码,只是为了好玩:

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'

感谢大家的耐心和帮助。

编辑:最好的答案是我们所有人:git status是瓷器(UI)。好的脚本与GIT管道相悖。这是最后的功能:

# 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'

请注意,只有提示符是特定于zsh的。在Bash中,它将是您的提示加"\$(parse_git_branch)"

这可能会更慢(对GIT的更多调用,但这是一个经验问题)但它不会被GIT中的更改打破(它们不会改变管道)。这对于一个好的剧本来说非常重要。

7 个答案:

答案 0 :(得分:5)

你应该使用Git“plumbing”命令来提取你想要的信息。 “瓷器”命令(例如git status)的输出可能会随着时间的推移而改变,但“管道”命令的行为会更加稳定。

使用瓷器接口,也可以在没有“bashisms”或“zshisms”的情况下完成(即=~匹配运算符):

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}"
}

将输出集成到提示符中仍然是特定于shell的(即转义或引用$(对于 bash zsh )并设置PROMPT_SUBST(对于的zsh ))。

答案 1 :(得分:2)

摆脱额外的}${git_status}}应为${git_status}


删除额外}后,我看到的唯一潜在问题是使用${BASH_REMATCH[1]}。您可以在zsh中使用它,但它需要启用该选项才能执行此操作。正如conditional expressions上的zsh文档所示,您需要使用类似

的内容
if [[ ${git_status} =~ ${pattern} ]]; then
  branch=${match[1]}
  echo "(${branch}${state})"
fi

答案 2 :(得分:2)

您可以使用数组match代替$BASH_REMATCH。你也可以逃脱额外的大括号。

未测试:

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
}

尝试一下,看看它是否有帮助。

答案 3 :(得分:1)

如果你不想学习zsh,我建议你使用另一种语言,比如Python,进行那种解析。

查看github上的git status Python parserzsh-git-prompt project,了解如何获得git的zsh提示。

答案 4 :(得分:1)

如果收到错误failed to compile regex: illegal byte sequence,则从IFS中删除NULL。 (将${IFS}替换为${IFS//$'\0'/})。

答案 5 :(得分:0)

可能这个zsh Git repository将包含可以给你一些线索的测试:

答案 6 :(得分:0)

如果有人有兴趣看到git-prompt功能的替代解决方案,我已经在github.com上发布了这个脚本,但是为了更容易,你可以从这里获得它。

它对我很有用,希望它对你也一样。

## 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;
  }

用法:

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\] '