在bash提示符中设置git状态的颜色

3
我正在尝试使用以下脚本设置我的bash提示符。一切都正常,但是在Git存储库中打印分支名称和分支状态以进行颜色标记的部分存在问题。颜色有些随意,但不言而喻的是,如果有未提交的文件,则为红色,如果有未暂存的文件,则为黄色,否则为绿色。它以白色打印出我想要的那部分。当我运行脚本的最后一部分时,在这里定义$branchStyle可以工作,但不在这里。我做错了什么?
prompt_git() {
  local s=""
  local branchName=""

  # check if the current directory is in a git repository
  if [ $(git rev-parse --is-inside-work-tree &>/dev/null; printf "%s" $?) == 0 ]; then

      # check if the current directory is in .git before running git checks
      if [ "$(git rev-parse --is-inside-git-dir 2> /dev/null)" == "false" ]; then

          # ensure index is up to date
          git update-index --really-refresh  -q &>/dev/null

          # check for uncommitted changes in the index
          if ! $(git diff --quiet --ignore-submodules --cached); then
              s="$s+";
          fi

          # check for unstaged changes
          if ! $(git diff-files --quiet --ignore-submodules --); then
              s="$s!";
          fi

          # check for untracked files
          if [ -n "$(git ls-files --others --exclude-standard)" ]; then
              s="$s?";
          fi

          # check for stashed files
          if $(git rev-parse --verify refs/stash &>/dev/null); then
              s="$s$";
          fi

      fi

      # get the short symbolic ref
      # if HEAD isn't a symbolic ref, get the short SHA
      # otherwise, just give up
      branchName="$(git symbolic-ref --quiet --short HEAD 2> /dev/null || \
                  git rev-parse --short HEAD 2> /dev/null || \
                  printf "(unknown)")"

      [ -n "$s" ] && s=" [$s]"

      printf "%s" "$1$branchName$s"
  else
      return
  fi
}

set_prompts() {

    local bold=$(tput bold)
    local reset=$(tput sgr0)
    local base05=$(tput setaf 188) # light grey
    local base08=$(tput setaf 210) # red
    local base0A=$(tput setaf 221) # yellow
    local base0B=$(tput setaf 114) # green

    if git rev-parse --git-dir >/dev/null 2>&1; then
        # check for uncommitted changes in the index
        if ! git diff-index --quiet --cached HEAD --ignore-submodules -- >&2; then
            branchStyle=$base08
        # check for unstaged changes
        elif ! git diff-files --quiet --ignore-submodules -- >&2; then
            branchStyle=$base0A
        else
            branchStyle=$base0B
        fi
    fi

    PS1+="\$(prompt_git \"$bold$base05 on $branchStyle\")" # git repository details

    export PS1
}

set_prompts
unset set_prompts

你有一个更短的测试案例能够展示这个问题吗?bash标签维基上有一些关于如何减少发布的代码大小的技巧。 - that other guy
@thatotherguy,k,我已经删除了脚本中我认为不必要的部分。实际上,prompt_git函数旨在查找存储库中的更改并添加一个字符串,以便您可以在提示符中看到这些更改,而在set_prompts函数中有一个不同的检查,确定分支是否具有未提交的更改或未暂存的更改,并相应地设置颜色。我对所有这些都在一个或多个函数中完成感到满意,无论哪种方式都是最好的结果。 - iamnewton
不要只删除脚本中不需要的内容,而是删除所有不必要的内容,以便重现您发布的特定颜色问题。例如,这是否足以重现该问题?echo "$(tput setaf 210)为什么这个文本是白色而不是粉色" - that other guy
@thatotherguy,所以我删除了在此示例中未使用的所有颜色,并对这些颜色进行了注释,因为说实话,颜色并不重要,我只想让提示有三种颜色变化,分别用于未提交更改、未暂存更改和其他情况。 - iamnewton
2个回答

3
将问题简化成最小的代码段以重现你所看到的问题是解决任何问题的好方法。这样做可以更容易地进行调试,更容易让其他人阅读和解决,并且会产生一个更普遍的问题,其他用户也可以从中受益。
例如,如果你研究你的问题,你会发现:
  • 它与prompt_git函数无关:当用一个简单的echo替换它时,同样的事情会发生。
  • 它与颜色无关:如果使用纯字符串,同样的事情会发生。
  • 它与未暂存或未提交的文件无关:如果跳过这些检查,同样的事情会发生。
  • 它与git完全无关:如果只比较目录,同样的事情会发生。
现在,我们可以使用一个小的代码示例编写一个问题,准确地说明了出现了什么问题:

我期望下面的代码段在我 cd /tmp后显示"in /tmp",但实际上提示保持空白。为什么它不更新?

set_prompts() { 
  message=""
  if [[ $PWD/ == /tmp/* ]]
  then
    message="in /tmp"
  fi
  PS1="\$(echo $message) \$"
}
set_prompts
unset set_prompts

这个问题相对容易阅读和回答:set_prompts 只会运行一次并且计算 $message 的值,然后它就会被取消设置并且再也不会执行。这就是为什么消息永远不会改变。

要让它工作,确保在每个提示之前重新运行它以重新生成它。这可以使用 PROMPT_COMMAND 完成:

set_prompts() { 
  PS1='\u@\h:\w '                 # <-- Reset PS1 before each run
  message=""
  if [[ $PWD/ == /tmp/* ]]
  then
    message="in /tmp"
  fi
  PS1="\$(echo $message) \$"
}    
PROMPT_COMMAND='set_prompts'      # <-- Run function before every prompt

这个代码可以正常运行,而且可以很容易地适应你实际的长代码。

1

并非所有终端都支持三位数字的颜色代码,有些终端仅支持在terminfo中声明的8种基本颜色。

Color       #define       Value       RGB
black     COLOR_BLACK       0     0, 0, 0
red       COLOR_RED         1     max,0,0
green     COLOR_GREEN       2     0,max,0
yellow    COLOR_YELLOW      3     max,max,0
blue      COLOR_BLUE        4     0,0,max
magenta   COLOR_MAGENTA     5     max,0,max
cyan      COLOR_CYAN        6     0,max,max
white     COLOR_WHITE       7     max,max,max

所以,我认为你的问题是使用了更高的颜色编号。你可以像这样输出终端颜色表:
( x=`tput op` y=`printf %$((${COLUMNS}-6))s`;for i in {0..256};do o=00$i;echo -e ${o:${#o}-3:3} `tput setaf $i;tput setab $i`${y// /=}$x;done; )

来自http://www.commandlinefu.com/commands/view/6533/print-all-256-colors-for-testing-term-or-for-a-quick-reference


我的支持256,所以你放置的脚本会输出256种颜色变化。 - iamnewton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接