LoginSignup
6
10

More than 5 years have passed since last update.

bashのprompt文字列をgit statusの状態で色変えする

Last updated at Posted at 2017-04-24

目指したもの

Cmderのプロンプト表示をmsys2でも表示したいです。
こいつは賢くて、現在のgitリポジトリ状態を色で教えてくれます。
以下の図はCmderのプロンプト表示です。


cmder1.PNG

gitリポジトリが汚れた(dirty)状態はブランチの色が赤


cmder2.PNG

gitリポジトリがきれいな(clean)状態はブランチの色が白


cmder_prompt.PNG

cmderでプロンプトを表すPROMPTという変数の、{git}{hg}とかいうやつがリポジトリを判断して色変えしているようです。


これをmsys2 shell上で行いたいです。

msys1.PNG

デフォルトのmsys2のプロンプト表示です。
ブランチ名の色変えどころか、ブランチ名の表示もありません。

環境

  • OS: Windows 10 64bit
  • ターミナルエミュレータ: Cmder
  • shell: MSYS2
  • git: version 2.12.1

私の環境だけでしょうか、有名だと思われるgit-prompt.shではうまく色変えができませんでした。

やること

使い方

  1. .bash_promptをホームディレクトリに作成します(内容は以下)。
  2. .bashrc(または.bash_profile)に.bash_promptを読み込ませるよう指示します(以下に例)。

.bash_promptの作成

以下をコピペってホームディレクトリ直下に保存し、.bashrcから読み込ませる(source ~/.bash_aliases)ようにします。

.bash_prompt
#!/bin/bash
#
# DESCRIPTION:
#
#   Set the bash prompt according to:
#    * the active virtualenv
#    * the branch/status of the current git repository
#    * the return value of the previous command
#    * the fact you just came from Windows and are used to having newlines in
#      your prompts.
#
# USAGE:
#
#   1. Save this file as ~/.bash_prompt
#   2. Add the following line to the end of your ~/.bashrc or ~/.bash_profile:
#        . ~/.bash_prompt
#
# LINEAGE:
#
#   Based on work by woods
#
#   https://gist.github.com/31967

# The various escape codes that we can use to color our prompt.
RED="\[\033[0;31m\]"
YELLOW="\[\033[1;33m\]"
GREEN="\[\033[0;32m\]"
BLUE="\[\033[1;34m\]"
LIGHT_RED="\[\033[1;31m\]"
LIGHT_GREEN="\[\033[1;32m\]"
WHITE="\[\033[1;37m\]"
LIGHT_GRAY="\[\033[1;30m\]"
COLOR_OCHRE="\[\033[38;5;95m\]"
COLOR_NONE="\[\e[0m\]"

# Detect whether the current directory is a git repository.
function is_git_repository {
  git branch > /dev/null 2>&1
}

# Determine the branch/state information for this git repository.
function set_git_branch {
  # Capture the output of the "git status" command.
  git_status="$(git status 2> /dev/null)"

  # Set color based on clean/staged/dirty.
  if [[ ${git_status} =~ "nothing to commit, working tree clean" ]]; then
    state="${GREEN}"
  elif [[ ${git_status} =~ "Changes to be committed:" ]]; then
    state="${YELLOW}"
  elif [[ ${git_status} =~ "Changes not staged for commit:" ]]; then
    state="${LIGHT_RED}"
  elif [[ ${git_status} =~ "Untracked files:" ]]; then
    state="${BLUE}"
  else
    state="${COLOR_OCHRE}"
  fi

  # Set arrow icon based on status against remote.
  remote_pattern="Your branch is (.*) of"
  if [[ ${git_status} =~ ${remote_pattern} ]]; then
    if [[ ${BASH_REMATCH[1]} == "ahead" ]]; then
      remote="^"
    else
      remote="v"
    fi
  else
    remote=""
  fi
  diverge_pattern="Your branch and (.*) have diverged"
  if [[ ${git_status} =~ ${diverge_pattern} ]]; then
    remote="^v"
  fi

  # Get the name of the branch.
  branch_pattern="^On branch ([^${IFS}]*)"
  if [[ ${git_status} =~ ${branch_pattern} ]]; then
    branch=${BASH_REMATCH[1]}
  fi

  # Set the final branch string.
  BRANCH="${state}(${branch})${remote}${COLOR_NONE} "
}

# Return the prompt symbol to use, colorized based on the return value of the
# previous command.
function set_prompt_symbol () {
  if test $1 -eq 0 ; then
      PROMPT_SYMBOL="${LIGHT_GRAY}\$${COLOR_NONE}"
  else
      PROMPT_SYMBOL="${LIGHT_RED}\$${COLOR_NONE}"
  fi
}

# Determine active Python virtualenv details.
function set_virtualenv () {
  if test -z "$VIRTUAL_ENV" ; then
      PYTHON_VIRTUALENV=""
  else
      PYTHON_VIRTUALENV="${LIGHT_GREEN}[`basename \"$VIRTUAL_ENV\"`]${COLOR_NONE} "
  fi
}

# Set the full bash prompt.
function set_bash_prompt () {
  # Set the PROMPT_SYMBOL variable. We do this first so we don't lose the
  # return value of the last command.
  set_prompt_symbol $?

  # Set the PYTHON_VIRTUALENV variable.
  set_virtualenv

  # Set the BRANCH variable.
  if is_git_repository ; then
    set_git_branch
  else
    BRANCH=''
  fi

  # Set the bash prompt variable.
  PS1="
${PYTHON_VIRTUALENV}${BLUE}@\h ${GREEN}\w${COLOR_NONE} ${BRANCH}
${PROMPT_SYMBOL} "
}

# Tell bash to execute this function just before displaying its prompt.
PROMPT_COMMAND=set_bash_prompt

実行結果

msys3.PNG

  • リポジトリがきれいな状態(ブランチの色がグリーン)
  • リポジトリが汚れていて、ステージングされていない状態(ブランチの色がレッド)
  • リポジトリが汚れていて、ステージングされいる状態(ブランチの色がイエロー)
  • イエローの状態でgit commitするとグリーンに戻ります。

msys4.PNG

  • リモートリポジトリとの差分確認を行い、aheadを^、behindをvの記号で教えてくれます。
  • git remote updateコマンドが必要かもしれません。

画像のgsコマンドは私のaliasでgit status --shortと同義です。

やったこと 

  • bash_prompt.shを今のgitのversionに合うように改造しました。
  • 見づらいと思うので、どんな改造をしたか興味がある人だけ見てください。
  • 行頭<マークが削除
  • 行頭>マークが追加
diff抜粋
# 白いボヤがかかったような文字らしい。まだどういう状態かは見ていない
31,33c31,34
> COLOR_OCHRE="\[\033[38;5;95m\]"

# "Changes not staged for commit:"の状態も増やした
# git アップデートにより微妙にメッセージが変更になっている
46c47
<   if [[ ${git_status} =~ "working directory clean" ]]; then
---
>   if [[ ${git_status} =~ "nothing to commit, working tree clean" ]]; then
48c49
<   elif [[ ${git_status} =~ "Changes to be committed" ]]; then
---
>   elif [[ ${git_status} =~ "Changes to be committed:" ]]; then
50c51
<   else
---
>   elif [[ ${git_status} =~ "Changes not staged for commit:" ]]; then
51a53,54
>   else
>     state="${COLOR_OCHRE}"


# '#'マークはgitのアップデートにより不要
55c58
<   remote_pattern="# Your branch is (.*) of"
---
>   remote_pattern="Your branch is (.*) of"

# 環境依存文字'↑'とか'↓'とか嫌い
58c61
<       remote="↑"
---
>       remote="^"
60c63
<       remote="↓"
---
>       remote="v"

# '#'マークはgitのアップデートにより不要
65c68
<   diverge_pattern="# Your branch and (.*) have diverged"
---
>   diverge_pattern="Your branch and (.*) have diverged"
71c74
<   branch_pattern="^# On branch ([^${IFS}]*)"
---
>   branch_pattern="^On branch ([^${IFS}]*)"

# $マークの色変え
84c87
<       PROMPT_SYMBOL="\$"
---
>       PROMPT_SYMBOL="${LIGHT_GRAY}\$${COLOR_NONE}"

# 好みの色変え
95c98
<       PYTHON_VIRTUALENV="${BLUE}[`basename \"$VIRTUAL_ENV\"`]${COLOR_NONE} "
---
>       PYTHON_VIRTUALENV="${LIGHT_GREEN}[`basename \"$VIRTUAL_ENV\"`]${COLOR_NONE} "
117c120
< ${PYTHON_VIRTUALENV}${GREEN}\u@\h ${YELLOW}\w${COLOR_NONE} ${BRANCH}
---
> ${PYTHON_VIRTUALENV}${BLUE}@\h ${GREEN}\w${COLOR_NONE} ${BRANCH}

ここに載っていないdiffはインデント変更とか簡単なものです。

よく見たら作成が6年も前、最後の更新が2011年12月…

今ではもっと工夫されたスクリプトありそう。
自分でひとまず作ってから、もっと最適化されたやつ見つけちゃうんだよなぁ。

追記2017/5/25

  • git statusで表示されるローカルリポジトリの状態がUntracked files:のときに、ブランチ名を青で表示する機能を追加しました。
  • git statusで表示されるリモートリポジトリの状態がYour branch and (.*) have divergedのときに、付加する記号をの環境依存文字から^vへ変更しました。
6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10