Customize Git Bash shell
Tags: bash, git, beginners, productivity
Published: 2021-10-31 16:27:24

Due to the need to maintain backward compatibility, newer features of Bash are rarely enabled by default. MinGW64 (Minimalist GNU for Windows x64) has to be configured to take full advantage of these features. Improve your productivity with several simple tweaks that can enhance Bash out-of-the-box without using external stuff. I will assume that Git for Windows and optionally also Windows Terminal are already installed. 

## Customize Startup Files
The Git bash shell is invoked as an interactive login shell for Git-only authentication access. Bash uses a few startup files to configure the shell environment for users. It will source files like `~/.bash_profile`, `~/.bash_login`, and `~/.profile` in the order given. The first readable file that exists is sourced.

### Bash Profile
1\. Create a `~/.bash_profile` file. The `.bash_profile` contains commands for setting the shell's environment variables. A `~/.bash_profile` can be used instead of `~/.profile` but is read by Bash only. Since the shell is interactive, the `~/.bashrc` file is not sourced. Refer to the [Bash Manual](https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html) for more information. Copy everything below into your own file.
```bash
# Source the ~/.bashrc file if it exists
if [ -f ~/.bashrc ]
then
    . ~/.bashrc
fi
```

### Bash shell Script
2\. Create a `~/.bashrc` file. The `.bashrc` file contains commands that are specific to the Bash shell. It is the best place for aliases and bash-related functions. Copy everything below into your own file.
```bash
# Git aliases
alias gs='git status -sb'
alias gcc='git checkout'
alias gcm='git checkout master'
alias gaa='git add --all'
alias gc='git commit -m $2'
alias push='git push'
alias gpo='git push origin'
alias pull='git pull'
alias clone='git clone'
alias stash='git stash'
alias pop='git stash pop'
alias ga='git add'
alias gb='git branch'
alias gl="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
alias gm='git merge'

# Bash aliases
alias .='cd .'
alias ..='cd ..'
alias ...='cd ../../'
alias ....='cd ../../../'
alias .....='cd ../../../../'
alias bashclear='echo "" > ~/.bash_history'
alias cls='clear'
alias ls='ls -F --color=auto --show-control-chars'
alias ll='ls -l'
alias ll.='ls -la'
alias lls='ls -la --sort=size'
alias llt='ls -la --sort=time'
alias rm='rm -iv'
alias work='cd /c/repos'

# Bash shell settings
# Typing a directory name just by itself will automatically change into that directory.
shopt -s autocd

# Automatically fix directory name typos when changing directory.
shopt -s cdspell

# Automatically expand directory globs and fix directory name typos whilst completing. 
# Note, this works in conjuction with the cdspell option listed above.
shopt -s direxpand dirspell

# Enable the ** globstar recursive pattern in file and directory expansions.
# For example, ls **/*.txt will list all text files in the current directory hierarchy.
shopt -s globstar

# Ignore lines which begin with a <space> and match previous entries.
# Erase duplicate entries in history file.
HISTCONTROL=ignoreboth:erasedups

# Ignore saving short- and other listed commands to the history file.
HISTIGNORE=?:??:history

# The maximum number of lines in the history file.
HISTFILESIZE=99999

# The number of entries to save in the history file.
HISTSIZE=99999

# Set Bash to save each command to history, right after it has been executed.
PROMPT_COMMAND='history -a'

# Save multi-line commands in one history entry.
shopt -s cmdhist

# Append commands to the history file, instead of overwriting it.
# History substitution are not immediately passed to the shell parser.
shopt -s histappend histverify
```

### Git Bash Prompt
The Git Bash prompt is set by a shell script called `git-prompt.sh` and can be found in the `c/Program\ Files/Git/etc/profile.d` directory. Notice that in lines 8-10, a custom `~/.config/git/git-prompt.sh` file will be sourced, if it exists. I believe that this is the recommended method to override the default settings.
```bash
# lines omitted
if test -f ~/.config/git/git-prompt.sh
then
	. ~/.config/git/git-prompt.sh
else
    # lines omitted
fi
# lines omitted
```

3\. Create a `~/.config/git/git-prompt.sh` file. The `git-prompt.sh` file contains commands for setting the title of the Git Bash terminal and the Bash prompt string. Copy everything below into your own file.
```bash
# Custom prompt settings
PROMPT_DIRTRIM=4                         # Shorten deep paths in the prompt
PS1='\[\033]0;Git | Bash v\v | \W\007\]' # set window title
PS1="$PS1"'\n'                           # new line
PS1="$PS1"'\[\033[30;45m\] [\A] '        # black text, magenta, 24h time
PS1="$PS1"'\[\033[30;42m\] \u '          # black text, green, user
#PS1="$PS1"'\[\033[30;42m\]@\h '          # black text, green, @host
PS1="$PS1"'\[\033[30;43m\] \w '          # black text, yellow, working director
if test -z "$WINELOADERNOEXEC"
then
    GIT_EXEC_PATH="$(git --exec-path 2>/dev/null)"
    COMPLETION_PATH="${GIT_EXEC_PATH%/libexec/git-core}"
    COMPLETION_PATH="${COMPLETION_PATH%/lib/git-core}"
    COMPLETION_PATH="$COMPLETION_PATH/share/git/completion"
    if test -f "$COMPLETION_PATH/git-prompt.sh"
    then
        . "$COMPLETION_PATH/git-completion.bash"
        . "$COMPLETION_PATH/git-prompt.sh"
        PS1="$PS1"'\[\033[97;46m\]'  # white text, cyan
        PS1="$PS1"'`__git_ps1`'      # bash function
    fi
fi
PS1="$PS1"'\[\033[0m\]'        # change color
PS1="$PS1"'\n'                 # new line
PS1="$PS1"'$ '                 # prompt: always $

# Git status options
# Shows * or + for unstaged and staged changes, respectively.
export GIT_PS1_SHOWSTASHSTATE=true

# shows $ if there are any stashes.
export GIT_PS1_SHOWDIRTYSTATE=true

# Shows % if there are any untracked files.
export GIT_PS1_SHOWUNTRACKEDFILES=true

# shows <, >, <>, or = when your branch is behind, ahead, diverged from,
# or in sync with the upstream branch, respectively.
export GIT_PS1_SHOWUPSTREAM="auto"
```


###  User Configuration
4\. Create a `~/.inputrc` file. This file contains commands to configure command history, directory display, and keyboard bindings using the built-in GNU Readline library. Refer to the [Bash Manual](https://www.gnu.org/software/bash/manual/html_node/Readline-Interaction.html), and [Readline Documentation](https://tiswww.case.edu/php/chet/readline/rltop.html) for more information.
```bash
# Disable beeps & bells, and do not display control characters.
set bell-style none
set echo-control-characters off

# The TAB key cycles forward through the completion choices.
# Press an arrow key, such as right-arrow, to choose a selection.
TAB: menu-complete

# The Shift-TAB key cycles backward through the completion choices.
# Like TAB, press an arrow key, such as right-arrow, to choose a selection.
"\e[Z": menu-complete-backward

# The first TAB key press will display a list that match the given prefix.
# The next TAB key press will start cycling through the available choices.
set menu-complete-display-prefix on

# Display completion matches upon the first press of the TAB key.
#set show-all-if-ambiguous on

#Enable colors when completing filenames and directories.
set colored-stats on

# Completion matches of multiple items highlight the matching prefix in color.
set colored-completion-prefix on

# Ignore case when completing.
set completion-ignore-case on

# Treat hypens and underscores as equivalent when completing.
set completion-map-case on

# Append the / character to the end of symlinked directories when completing.
set mark-symlinked-directories on

# Enable incremental history navigation with the UP and DOWN arrow keys.
# This will use the already typed text as a required prefix.
"\e[A": history-search-backward
"\e[B": history-search-forward
```

The Readline library also provides several useful shortcuts. 

|  Keyboard shortcut  |  Description  |
|-------------------|:-------------:|
| Control-A | Go to beginning of line. |
| Control-E | Go to the end of the line. |
| Alt-B | Go back one word. |
| Alt-F | Go forward on word. |
| Alt-Backspace | Delete backward one word. |
| Alt-D | Delete forward one word. |
| Control-R | Search back through history. |
| Control-R | Cycle backward through history. |
| Control-Shift-R | Cycle forward through history. |
| Alt-. | Append an argument of the previous command. |

### Finished Result
5\. After the customization is done, restart the terminal or open a new Git Bash tab in Windows Terminal. Your Git Bash should look similar to the result below.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nklsu0l3xh1nif49hsgf.png)

## Bash Utilities
Some Bash utilities are also included with Git for Windows and may be used to enhance your Git experience if the default behavior is not desired. These utilities will need to be configured in each independent development environment. Refer to the [Pro Git Book](https://git-scm.com/book/cs/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash) for more information.

The *git-completion* and *git-prompt* scripts can be found in the following directory. `/c/Program\ Files/Git/mingw64/share/git/completion/`  Copy the `git-completion.bash` and `git-prompt.sh` to your home directory.

To use the scripts append the following lines to the `~/.bashrc` file. 
```bash
# Enable tab completion for Git commands
source ~/.git-completion.bash
# Change bash prompt to display current Git branch and status
source ~/.git-prompt.sh
```