Terminus by Warp
Prompt Show Git Branch In Prompt

Prompt Show Git Branch In Prompt

 Gabriel Manricks
Gabriel Manricks
Chief Architect at ClearX

The short answer

The appearance of the terminal prompt is controlled by an environment variable named [.inline-code]PS1[.inline-code], which the shell evaluates each time the prompt is displayed.

To change your prompt to include the current Git branch, you can start by opening your shell's configuration file using your favorite text editor; for Bash, it is [.inline-code]~/.bashrc[.inline-code], and for Zsh, it is [.inline-code]~/.zshrc[.inline-code]:

 $ vim ~/.zshrc

Define the following [.inline-code]getBranch[.inline-code] function into it:

 getBranch() {
    git rev-parse --abbrev-ref HEAD 2> /dev/null
}

Where:

  • The [.inline-code]git rev-parse --abbrev-ref HEAD[.inline-code] command fetches the name of the current branch.
  • The [.inline-code]2> /dev/null[.inline-code] redirection is used to discard any error messages, for example, if the current directory is not a Git repository.

Integrate this function into the [.inline-code]PS1[.inline-code] environment variable:

 export PS1="$PS1 \$(getBranch) "

Where:

  • The [.inline-code]export[.inline-code] command sets an environment variable.
  • The [.inline-code]$PS1[.inline-code] variable contains the current prompt settings.
  • The [.inline-code]$(getBranch)[.inline-code] expression will be replaced by the [.inline-code]getBranch[.inline-code] command output.
  • The [.inline-code]\[.inline-code] ensures that the [.inline-code]$(getBranch)[.inline-code] expression evaluates dynamically each time the prompt is displayed rather than being pre-evaluated and stored as a string on terminal' start up.

Note that if you are using Zsh as your terminal, you will need to enable command substitution within the prompt using the [.inline-code]setopt[.inline-code] command as follows:

 setopt PROMPT_SUBST;

After editing your shell config file, you will need to reload your shell’s configuration by opening a new terminal or by running the following [.inline-code]source[.inline-code] command:

$ source path/to/shell_config

[#warp-context-chips] Easily change the prompt using the Warp Context Chips feature [#warp-context-chips]

If you’re using Warp as your terminal, you can easily change your terminal's prompt using the Warp Context Chips feature:

The Warp Custom Prompt is a GUI-based feature that allows you to customize your shell using a list of pre-configured prompts that you can easily combine through a system of drag and drop, including timestamp, remote login, git branch, and more.

Just right-click your prompt and click on “Edit Prompt” to bring up the visual custom prompt editor. 

These prompt chips are context-aware, so for example, if you add the “uncommitted files” chip, then only when inside a git directory you will have a section on the number of uncommitted files, or if you add the Kubernetes context it will only appear when running a kubectl command.

[#extending-your-git-prompt] Extending your Git prompt [#extending-your-git-prompt]

The goal of a good Git prompt is to provide as much helpful context about the repository you are currently in without requiring you to run any commands manually, like how a prompt displays the current working directory so that you don’t need to check where you are manually.

In the context of Git, some relevant contextual information is:

  • The branch name - to make sure you are working on the correct branch
  • The status of the branch - to allow you to know if you need to commit something
  • The difference in commits between the local and remote repositories - to see if you need to pull or push any changes

Commits ahead or behind upstream

To get the number of commits you are ahead or behind the remote branch, you can use:

 $ git rev-list --count --left-right @{upstream}...HEAD
12    6

The command will output two columns: the first will be the number of commits the upstream (origin) is ahead of your local branch, and the second is the number of commits you are ahead of the remote branch. 

Using this, you can create a function in your shell’s config file ([.inline-code]~/.zshrc[.inline-code]):

gitUpstreamPosition() {
    local commitCount=$(git rev-list --count --left-right @{upstream}...HEAD 2> /dev/null)
    if [ -n "$commitCount" ]; then
       local behindCount=$(echo -n "$commitCount" | cut -f1)
       local aheadCount=$(echo -n "$commitCount" | cut -f2)
       if [ "$behindCount" != "0" ]; then
           echo -n " ${behindCount}↓"
       fi
       if [ "$aheadCount" != "0" ]; then
          echo -n " ${aheadCount}↑"
       fi
    fi
}

Where:

  • [.inline-code]local commitCount=$(...)[.inline-code] runs the command and stores the results in a local variable called [.inline-code]commitCount[.inline-code]
  • [.inline-code] if [ -n "$commitCount" ];[.inline-code] checks if the value is not an empty string
  • [.inline-code]echo -n $commitCount | cut -f1[.inline-code] will cut the first column, which is the number of commits behind the remote branch. The value is stored in a variable called [.inline-code]behindCount[.inline-code]
  • [.inline-code]local aheadCount=$(...)[.inline-code] same is done for the second column, which is the number of commits ahead of the remote branch.
  • [.inline-code]if [ "$behindCount" != "0" ];[.inline-code] check only to display something if the value is different than zero.
  • [.inline-code]echo -n " ${behindCount}↓"[.inline-code] print out the number plus a down arrow as a symbol for commits that need to be pulled.

Working Tree Status

Another common use case is to display the status of your work tree to see if there are changes to commit or if you are in a clean state. The command to get the status of the working tree is:

 $ git status --porcelain
A  file.txt
MM demo.bin
D  README.md

Many git commands have a [.inline-code]--porcelain[.inline-code] flag, which outputs the data in an easier-to-parse format. For git status, the porcelain flag will cause the output only to include changed files without any extra text, and for each line, you will have two letters describing the change followed by a space and the file name.

The first letter is the staged change status, and the second is the unstaged change status. The exception to this is new files that have never been tracked (added) to Git; they will have a question mark in each column.

So, to see if there are any staged changes, you can simply check to see if, in any of the rows, there is a line with a letter (other than a question mark) in the first character space:

 $ git status --porcelain | grep '^[^? ]'

Where the [.inline-code]grep[.inline-code] regular expression is:

  • [.inline-code]^[.inline-code] - means the match must start at the beginning of a line
  • [.inline-code][^? ][.inline-code] - brackets specify a group of characters to match, and the [.inline-code]^[.inline-code] reverses the selection, so any character not matching a question mark or space.

A prompt function to display symbols for these different kinds of changes would look something like the following:

gitStatusSymbols() {
    local gitstatus=$(git status --porcelain 2> /dev/null)
    if [ -n "$gitstatus" ]; then
         local statusString="";
         if [ -n "$(echo "$gitstatus" | grep '^[^? ]')" ]; then
                statusString="$statusString$GREEN+$BLANK"
         fi
         if [ -n "$(echo "$gitstatus" | grep '^.[^? ]')" ]; then
                statusString="$statusString$RED*$BLANK"
         fi
         if [ -n "$(echo "$gitstatus" | grep '^[?][?]')" ]; then
                statusString="$statusString?"
         fi
         echo -e " $statusString"
    fi
}
RED='%F{red}'
GREEN='%F{green}'
BLANK='%f'

Where:

  • The first line gets the status output, handling errors
  • [.inline-code]if [ -n "$gitstatus" ];[.inline-code] checks if the value is not empty
  • [.inline-code]local statusString="";[.inline-code] prepares a variable to hold the statuses
  • The function then checks for three kinds of changes using grep and a regular expression to test for staged changes, unstaged changes, and new files
  • For each of these cases, the function appends the desired symbol to the output variable
  • [.inline-code]echo -e " $statusString"[.inline-code] outputs the final results, prepending the value with a space to fit well with the rest of the prompt.
  • The last three lines hold variables with the escape sequence for adding color to the terminal output.

For Bash instead of Zsh, the variables for color should be:

GREEN='\033[32m'
RED='\033[31m'
BLANK='\033[0m'

Tying it all together

To wrap the above two functions into a single string along with the branch name you can create another function like the following:

 gitPrompt() {
    local branchName=$(git rev-parse --abbrev-ref HEAD 2> /dev/null)
    if [ -n "$branchName" ]; then
       echo -e " [🌱 ${branchName}$(gitStatusSymbols)$(gitUpstreamPosition)]"
    fi
}

This function gets the current branch name, and if the value isn’t blank (i.e., we are in a Git directory), it will output the branch name between square brackets along with the output of the two other functions. It is worth noting the [.inline-code]${}[.inline-code] with curly braces prints out a variable, whereas [.inline-code]$()[.inline-code] with parentheses runs a command/function and outputs the results.

This function can then be used by adding to your shell’s config file:

 export PS1="\u@\h \w\$(gitPrompt)> "

Where:

  • [.inline-code]\u[.inline-code] prints the current user
  • [.inline-code]\h[.inline-code] prints the hostname 
  • [.inline-code]\w[.inline-code] prints the current working directory
  • [.inline-code]$(gitPrompt) prints the output of the [.inline-code]gitPrompt[.inline-code] function

For Zsh, you will also need to enable prompt substitution as described above:

 setopt  PROMPT_SUBST

[#git-prompt-script] Git Prompt Script [#git-prompt-script]

Git has released an official utility that can be used to add Git info easily into your terminal prompt. To get started, you need to download the script itself:

$ curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh -o ~/git-prompt.sh

And then edit your shells configuration (~/.zshrc) with the following:

 source ~/.git-prompt.sh

That loads in a shell function called [.inline-code]__git_ps1[.inline-code], which prints out git information primarily to be used in prompts. To add it to your prompt, you can include it in your PS1 variable:

 export PS1="$PS1\$(__git_ps1 \" (%s)\")> "

The [.inline-code]__git_ps1[.inline-code] function accepts an optional format string parameter used to style the output. The example above sends [.inline-code]” (%s)”[.inline-code] where we will get a string that starts with a space and then parenthesis, and within the parenthesis, the [.inline-code]%s[.inline-code] will be replaced by the [.inline-code]__git_ps1[.inline-code] results. The advantage to using a format string instead of just hard coding the space and parenthesis is that if you are not in a Git repository, it will be omitted completely.

For Zsh, you will also need to enable prompt substitutions:

 setopt PROMPT_SUBST;

By default, this script will only display the git branch, but you can enable other features by setting specific environment variables.

[.inline-code]GIT_PS1_SHOWDIRTYSTATE[.inline-code] will cause the prompt to include the working tree status[.inline-code]GIT_PS1_SHOWUNTRACKEDFILES[.inline-code] will show if there are new untracked files[.inline-code]GIT_PS1_SHOWUPSTREAM[.inline-code] can be used to show commits ahead and behind your upstream

For example, add to your [.inline-code]~/.zshrc[.inline-code]

 export GIT_PS1_SHOWDIRTYSTATE=true

These are just a few of the options. You can view more info in the script comments here.

[#advanced-prompt-toolkits] Advanced Prompt Toolkits [#advanced-prompt-toolkits]

Designing a truly dynamic and interactive prompt that reacts to different tools like Docker, Git, Python, Node.js, etc., is a complex task. Each tool has nuances and design decisions (not to mention supporting multiple terminals like bash/zsh). Luckily, there are very popular projects that work on just this.

[#starship] Starship [#starship]

One such project is called Starship, which supports over 80 different tools, smart defaults out of the box, and the ability to customize many different settings in each.

To install Starship, you can run:

$ curl -sS https://starship.rs/install.sh | sh

Then, to get it running in Bash, add the following to your [.inline-code]~/.bashrc[.inline-code]:

 eval "$(starship init bash)"

And for Zsh, you would add to your [.inline-code]~/.zshrc[.inline-code]:

 eval "$(starship init bash)"

It is also recommended to install a NerdFont from here, which are regular fonts with the symbols replaced with popular development icons from icon frameworks like Devicons, Font Awesome, Material Design, and more.

Customising Starship

To customize Starship prompt, create a file [.inline-code]~/.config/starship.toml[.inline-code] with your configuration. Starship has both high-level settings for designing the prompt's format and granular per-tool options.

For example, if you would like to add the current Kubernetes context to your prompt, you can add the following to your [.inline-code]~/.config/starship.toml[.inline-code] file:

[kubernetes]
disabled = false
format = '[${symbol}k8s $context]($style) in '

Each tool in Starship has its own settings and variables. For Kubernetes, you have variables like context, namespace, user, and cluster; in the example above, we display the current Kubernetes context.

There are also configuration variables per tool, like symbol and style, which we used here; symbol defaults to a Kubernetes icon, and the style defaults to “cyan bold”. In Starship, to customize colors of text, you use the format [.inline-code][<text to color>](<style>)[.inline-code]; everything between the square brackets will receive the style defined in the parentheses.

You can find more info about starship configuration for Kubernetes and other tools here.

There are also presets that are like themes; these are complete [.inline-code]starship.toml[.inline-code] configurations you can just copy and use. You can find some presets on the official Starship site here.

[#pk10] Powerlevel10K (P10K) [#pk10]

If you are using ZSH, another popular off-the-shelf prompt is PowerLevel10K; like Starship, it has extensive support for many different tools and contexts.

To install P10K, you can run:

 $ git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k
$ echo 'source ~/powerlevel10k/powerlevel10k.zsh-theme' >>~/.zshrc

The first line clones the repository into your HOME directory, and the second command adds a line to your [.inline-code]~/.zshrc[.inline-code] file to load P10K.

Unlike other prompt kits like Starship, where you start off with the defaults and then customize it later, with P10K, you are greeted with a setup wizard the first time P10K is loaded. This setup wizard visually guides you through the different customization options, allowing you to get it set up just how you like it very quickly.

You can get back to this setup wizard at any time by running [.inline-code]p10k configure[.inline-code]

Experience the power of Warp

  • Write with an IDE-style editor
  • Easily navigate through output
  • Save commands to reuse later
  • Ask Warp AI to explain or debug
  • Customize keybindings and launch configs
  • Pick from preloaded themes or design your own
brew install --cask warp
Copied!
Join the Windows waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.
Join the Linux waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.
Join the Linux waitlist or join the Windows waitlist
Join the Windows waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.