my_knowledge.ko

Linux | Debug, Analyze, Trace | Tech | etc...

git の状態(ブランチ名、未追跡ファイルなど)を bash プロンプトに表示する方法

前提

表示例では、リモートの git リポジトリを clone したディレクトリが存在することを前提とします。

補足:環境情報

# uname -r
5.12.9-300.fc34.x86_64

# cat /etc/fedora-release
Fedora release 34 (Thirty Four)

# git --version
git version 2.31.1

# bash --version
GNU bash, version 5.1.0(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

設定方法

~/.bashrc などに次の内容を設定し、source ~/.bashrc などで設定を読み込む。環境変数は適宜コメントアウトする想定で、各環境変数に対応した機能の説明は後述する。

なお、git-prompt.sh は git の公式で用意されているスクリプトで、私の環境では (おそらく) git インストール時に上記パスに配置されていた。環境にっては配置パスが異なる可能性があるので注意。スクリプトが存在しない場合は git/git-prompt.sh at v2.31.1 · git/git · GitHub から当該スクリプトを取得してくる必要がある。

if [ -f "/usr/share/git-core/contrib/completion/git-prompt.sh" ]; then
        . /usr/share/git-core/contrib/completion/git-prompt.sh

        # プロンプト表示フォーマット
        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '

        # 未追跡ファイル (%)
        #GIT_PS1_SHOWUNTRACKEDFILES=true

        # ステージ(+), 未ステージ(*)
        #GIT_PS1_SHOWDIRTYSTATE=true
        
        # スタッシュ ($)
        #GIT_PS1_SHOWSTASHSTATE=true

        # アップストリームとの差分状態
        #GIT_PS1_SHOWUPSTREAM="auto"

        # 区切り文字
        #GIT_PS1_STATESEPARATOR=':'

        # sparse-checkout 関連
        #GIT_PS1_OMITSPARSESTATE=true
        #GIT_PS1_COMPRESSSPARSESTATE=true

        # 特定タグ、コミット、ブランチをチェックアウトした時の表示
        #GIT_PS1_DESCRIBE_STYLE=branch

        # 色付きで表示
        #GIT_PS1_SHOWCOLORHINTS=true
        #PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
fi

上記設定については、git-prompt.sh のコメント(公式の設定方法)を参考にしている。スクリプト内には、各環境変数についての説明もあるが、これについては各環境変数の個所で記載する。

上記設定方法の説明個所

#    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
#    2) Add the following line to your .bashrc/.zshrc:
#        source ~/.git-prompt.sh
#    3a) Change your PS1 to call __git_ps1 as
#        command-substitution:
#        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#        ZSH:  setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
#        the optional argument will be used as format string.
#    3b) Alternatively, for a slightly faster prompt, __git_ps1 can
#        be used for PROMPT_COMMAND in Bash or for precmd() in Zsh
#        with two parameters, <pre> and <post>, which are strings
#        you would put in $PS1 before and after the status string
#        generated by the git-prompt machinery.  e.g.
#        Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
#          will show username, at-sign, host, colon, cwd, then
#          various status string, followed by dollar and SP, as
#          your prompt.
#        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
#          will show username, pipe, then various status string,
#          followed by colon, cwd, dollar and SP, as your prompt.
#        Optionally, you can supply a third argument with a printf
#        format string to finetune the output of the branch status

表示例

設定前のプロンプトは次のとおり。

[root@localhost sandbox]#

共通 (特定の環境変数に依存しない)

ブランチ名
[root@localhost sandbox(main)]#
特定の操作時

merge, rebase, revert, cherry-pick, bisect 実行中は、 |<OPERATION-NAME> と表示される。

例) bisect

[root@localhost sandbox (main)]# git bisect start
[root@localhost sandbox (main|BISECTING)]#

上記の説明個所

# When there is an in-progress operation such as a merge, rebase,
# revert, cherry-pick, or bisect, the prompt will include information
# related to the operation, often in the form "|<OPERATION-NAME>".

GIT_PS1_SHOWUNTRACKEDFILES=true:未追跡ファイル (%)

[root@localhost sandbox(main)]# touch file
[root@localhost sandbox(main %)]#

上記環境変数の説明個所

# If you would like to see if there're untracked files, then you can set
# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
# files, then a '%' will be shown next to the branch name.  You can
# configure this per-repository with the bash.showUntrackedFiles
# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is
# enabled.

GIT_PS1_SHOWDIRTYSTATE=true:ステージ(+), 未ステージ(*)

ステージ (+)

[root@localhost sandbox(main)]# touch file
[root@localhost sandbox(main)]# git add file
[root@localhost sandbox(main +)]# 

未ステージ (*)

[root@localhost sandbox(main +)]# git commit -m "test"
[root@localhost sandbox(main)]# echo test > file
[root@localhost sandbox(main *)]#

上記環境変数の説明個所

# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
# unstaged (*) and staged (+) changes will be shown next to the branch
# name.  You can configure this per-repository with the
# bash.showDirtyState variable, which defaults to true once
# GIT_PS1_SHOWDIRTYSTATE is enabled.

GIT_PS1_SHOWSTASHSTATE=true:スタッシュ ($)

[root@localhost sandbox(main)]# touch file
[root@localhost sandbox(main)]# git add file
[root@localhost sandbox(main)]# git commit -m "test"
[root@localhost sandbox(main)]# git stash
Saved working directory and index state WIP on master: c844d84 test
[root@localhost sandbox(main $)]#

上記環境変数の説明個所

# You can also see if currently something is stashed, by setting
# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
# then a '$' will be shown next to the branch name.

GIT_PS1_SHOWUPSTREA=<value>:アップストリームとの差分状態

<value>"auto" を指定した例。

差分なし(=)

[root@localhost sandbox(main=)]# 

遅れ(<)

// アップストリーム側のファイルなど修正した状態で
[root@localhost sandbox (main=)]# git fetch
[root@localhost sandbox (main<)]# 

先行(>)

[root@localhost sandbox (main=)]# touch file
[root@localhost sandbox (main=)]# git add file
[root@localhost sandbox (main=)]# git commit -m "test"
[root@localhost sandbox (main>)]# 

分岐(<>)

// ローカルが先行し、アップストリーム側のファイルなど修正した状態で
[root@localhost sandbox (main>)]# git fetch
[root@localhost sandbox (main<>)]# 

上記以外の <value> としては verbose, name, legacy, git, svn がある。

上記環境変数の説明個所

# If you would like to see the difference between HEAD and its upstream,
# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
# indicates you are ahead, "<>" indicates you have diverged and "="
# indicates that there is no difference. You can further control
# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
# of values:
#
#     verbose       show number of commits ahead/behind (+/-) upstream
#     name          if verbose, then also show the upstream abbrev name
#     legacy        don't use the '--count' option available in recent
#                   versions of git-rev-list
#     git           always compare HEAD to @{upstream}
#     svn           always compare HEAD to your SVN upstream

GIT_PS1_STATESEPARATOR=<value>:区切り文字

<value>: を指定し、GIT_PS1_SHOWUNTRACKEDFILES=true を設定した例。

[root@localhost sandbox (main)]# touch file
[root@localhost sandbox (main:%)]#

なお、<value> のデフォルトは空白。

上記環境変数の説明個所

# You can change the separator between the branch name and the above
# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
# is SP.

GIT_PS1_*SPARSESTATE=true:sparse-checkout 関連

初期状態 (ここは環境変数に依存しない)

[root@localhost sandbox (main)]# git config core.sparsecheckout true
[root@localhost sandbox (main|SPARSE)]#

GIT_PS1_COMPRESSSPARSESTATE=true を設定すると ? に短縮可能。

[root@localhost sandbox (main)]# git config core.sparsecheckout true
[root@localhost sandbox (main ?)]# 

GIT_PS1_OMITSPARSESTATE=true を設定すると省略可能。

[root@localhost sandbox (main)]# git config core.sparsecheckout true
[root@localhost sandbox (main)]# 

上記環境変数の説明個所

# When the repository has a sparse-checkout, a notification of the form
# "|SPARSE" will be included in the prompt.  This can be shortened to a
# single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
# by setting GIT_PS1_OMITSPARSESTATE.

GIT_PS1_DESCRIBE_STYLE=<value>:特定タグ、コミット、ブランチをチェックアウトした時の表示

<value>branch を指定した例。デフォルトは tag

[root@localhost sandbox (main)]# git tag v1.0.0
[root@localhost sandbox (main)]# git checkout v1.0.0 
[root@localhost sandbox ((tags/v1.0.0))]

上記以外の <value> としては contains, describe がある。

上記環境変数の説明個所

# If you would like to see more information about the identity of
# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
# to one of these values:
#
#     contains      relative to newer annotated tag (v1.6.3.2~35)
#     branch        relative to newer tag or branch (master~4)
#     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
#     tag           relative to any older tag (v1.6.3.1-13-gdd42c2f)
#     default       exactly matching tag

GIT_PS1_SHOWCOLORHINTS=true:色付きで表示

bash の場合、PROMPT_COMMAND が有効の時にのみ、この環境変数が適用される。

f:id:Kernel_OGSun:20210918223503p:plain

上記環境変数の説明個所

# If you would like a colored hint about the current dirty state, set
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd in Bash,
# but always available in Zsh.

参考