Jason McCreary
Jason McCreary

Reputation: 72961

Customize colors for __git_ps1 with GIT_PS1_SHOWCOLORHINTS

What I have tried

I have updated my prompt to include the branch name using __git_ps1. In addition, I set GIT_PS1_SHOWCOLORHINTS.

The problem

The prompt appears correctly. However, the branch color is always green. I expected a dirty branch to be red.

The docs state:

The colors are based on the colored output of "git status -sb"

I found and reviewed How to colorize git-status output? But I'm not sure what options I'd need to change...

The question

Is it possible to change the branch color to be green for a clean branch and red for a dirty branch? If so, how?

Upvotes: 15

Views: 13608

Answers (3)

jirislav
jirislav

Reputation: 359

The way I have solved this issue was to write a short formatting function, which:

  1. works with PS1
  2. colorizes even the branch
  3. customizes messages/notes to include
  # Craft some nice coloured git status
  __fancy_git_status() {
    local STATUS COLOR NOTE GIT_PS
    STATUS=$(git status -sb --ignore-submodules 2>/dev/null)
    GIT_PS=$(if test $? -eq 0; then
      if grep -q '^A' <<<"$STATUS"; then
        COLOR=${COLOR_INTENSE_GREEN}
        NOTE=" ${COLOR_YELLOW}staged 4 commit$COLOR"
      elif grep -q '^ M' <<<"$STATUS"; then
        COLOR="${COLOR_GREEN}"
        NOTE=" ${COLOR_ORANGE}with changes$COLOR"
      else
        COLOR="${COLOR_INTENSE_GREEN}"
      fi
      __git_ps1 "${GIT_PS1_PREFIX}$COLOR⎇  %s${NOTE:-}"
    fi)
    test -n "$GIT_PS" && echo "$GIT_PS" || echo -e "${GIT_PS1_PREFIX}${COLOR_GRAY}not found"
  }

  PS1="..."  # Your preferred PS1 preceding the git information

  PS1+="\n"
  PS1+="${COLOR_DARK_GREEN}\$(__fancy_git_status)\n${COLOR_RESET}"

  PS1+="\\$ "

Here's how it looks in my terminal with clean branch:

showcase of defined PS1 function call - clean state

Dirty, but not staged:

showcase of defined PS1 function call - dirty state

Staged for commit:

showcase of defined PS1 function call - staged state

Upvotes: 0

Chris
Chris

Reputation: 136880

The colours shown by __git_ps1 for dirty branches don't affect the branch name; they affect the "dirty state indicator". In addition to enabling colours, if you enable this indicator you will see a red asterisk for a dirty branch:

old-prompt $ bash --noprofile --norc
bash-4.2$ source /etc/bash_completion.d/git-prompt
bash-4.2$ export GIT_PS1_SHOWCOLORHINTS=1
bash-4.2$ export GIT_PS1_SHOWDIRTYSTATE=1
bash-4.2$ export PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
chris@machine:~/path/to/dir (master *)$

There is no way to change the colour of the branch name based on dirty status without modifying the git-prompt.sh code, or providing your own function.

Note that this works with export PROMPT_COMMAND but not export PS1.

Upvotes: 17

Karl
Karl

Reputation: 91

I was able to achieve a decent solution by:
1. Cloning the latest git source, to obtain and install a recent git-prompt.sh (Your distro may already have an up-to-date script)
2. Removing the check that is stopping the script from inserting color codes in the output string.
3. Altering my .bashrc to include a call to __git_ps1 with some formatting options to alter my terminal prompt text.

Commit and documentation, including specific files and edits I made: https://github.com/karlapsite/git/commit/b34d9e8b690ec0b304eb794011938ab49be30204#diff-a43cc261eac6fbcc3578c94c2aa24713R449

Now, my console has all of the information I wanted: I can open a terminal, and cd into any git repo:
$ cd ~/Github/git user@hostname:~/Github/git:(master)$ # 'master' is green

And the when I checkout a hash, and move into a detached head state:
$ git checkout bca18110 user@hostname:~/Github/git:(bca1811...)$ # the commit hash is red

I needed to follow this answer: https://stackoverflow.com/a/13997892/4717806 to have bash properly re-interpret the color codes after each command, but my terminal is intact, linewrapping still works, and my prompt is colored the way I wanted!

Upvotes: 4

Related Questions