Print Git Status in Your Tmux Statusbar
Tags: linux, git, tmux, minimal
Published: 2021-08-18 04:14:15

---
title: Print Git Status in Your Tmux Statusbar
published: true
description: Dependency-free, minimalist, and portable implementation to show git status info in the tmux statusbar
tags: linux, git, tmux, minimal
//cover_image: https://direct_url_to_image.jpg
---

## Table of Contents

- [Problem](#problem)
- [Solution](#solution)
  - [Bash Function](#bash-function)
  - [Git Alias](#git-alias)
  - [Tmux](#tmux)
- [Conclusion](#conclusion)

## Problem

I recently wanted to show git branch and status information of the project I am wokring on in tmux statusbar. 

We can use one of the many open source projects to achieve this (see the [Conclusion](#conclusion) for honorable mentions), but I prefer a minimalist approach for simplicity and portability.

Naturally, I know I can invoke any shell command from my `.tmux.conf` using the `#(<shell command>)` syntax.

For example, `set -g status-right '#(echo "hello world")'` will print `hello world` in the right corner of your tmux statusbar, which is located at `bottom` by default.

But, doing something like `set -g status-right '#(git branch)'` didn't work. This is because the command is running in a different shell context, like running `sh -c "git branch"`. The current directory is simply not passed to the sub-shell command.

Furthermore, `git branch` only prints the branch name. We need a custom bash function to print symbols indicating if there are modified files, staged files, stashes, and/or untracked files.

## Solution

Similar to how you can print any information in a [`.bash_prompt`](https://github.com/pbnj/dotfiles/blob/5dbc2c665db081a4ffe07dea63902e7cc62f9fd3/bash/.bash_prompt) via custom bash functions, so too can we implement a function that is invoked as a git sub-command via [aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases).

### Bash Function

The function we will use for this is borrowed from [jessfraz/dotfiles](https://github.com/jessfraz/dotfiles/blob/master/.bash_prompt).

If we simply join all the lines and escape the double-quotes, it looks like this:

```
prompt_git() { local s=''; local branchName=''; if [ \"$(git rev-parse --is-inside-work-tree &>/dev/null; echo \"${?}\")\" == '0' ]; then if [ \"$(git rev-parse --is-inside-git-dir 2> /dev/null)\" == 'false' ]; then if [[ -O \"$(git rev-parse --show-toplevel)/.git/index\" ]]; then git update-index --really-refresh -q &> /dev/null; fi; if ! git diff --quiet --ignore-submodules --cached; then s+='+'; fi; if ! git diff-files --quiet --ignore-submodules --; then s+='!'; fi; if [ -n \"$(git ls-files --others --exclude-standard)\" ]; then s+='?'; fi; if git rev-parse --verify refs/stash &> /dev/null; then s+='$'; fi; fi; branchName=\"$(git symbolic-ref --quiet --short HEAD 2> /dev/null || git rev-parse --short HEAD 2> /dev/null || echo '(unknown)')\"; echo \"(${1}${branchName} ${s})\"; else return; fi; }
```

### Git Alias

Now, you can put this one-liner into a git alias in your `.gitconfig` or `~/.config/git/config`, like this:

```text
[alias]
    prompt = !"prompt_git() { ... }; prompt_git"
```

_Tip: alternatively, you can copy/paste the bash_prompt function into a shell script file prefixed with `git-`, like `git-prompt`, placed somewhere in your `$PATH`. This allows you to call it as if it were a standard git subcommand as well, like `git prompt`_.

Note that we invoke/execute the function after defining it.

To test this, simply run: 

```sh
$ git prompt
```

It should return the branch name and indicators based on your status, like:

```text
(branch +!$?)
```

### Tmux

Now, we can easily call a git command to show this information, but we also need to pass a `-C` flag with a path to the repo in question. Fortunately, tmux gives us the path of the current pane in a special variable called `#{pane_current_path}`.

So, our status bar configuration in tmux may look like:

```sh
set -g status-right '#(git -C #{pane_current_path} prompt)'
```

#### Bonus Tip

Did you know tmux has 2 different "status bars"? 

I like to put any global information, or information that does not change between panes, in my `status-right`. This includes date, time, cpu, and memory.

Any pane-specific information, I prefer to put it in my `pane-border-format`. This includes current working directory and git status information.

Example:

```text
set -g status-right-length 200
# show [prefix] when activated/pressed + mem/cpu load + date/timestamp
set -g status-right "#{?client_prefix,#[reverse][prefix]#[noreverse],}  #(tmux-mem-cpu-load --interval 1) [%A %Y-%m-%d %l:%M %p]"

set -g pane-border-status top
set -g pane-border-format ' #{pane_current_path} #(git -C #{pane_current_path} prompt) '
```

## Conclusion

If you are a minimalist like me, I hope this helps you configure and customize your tmux to best suit your needs, workflow, and productivity.

If you were hoping to discover tools or utilities to conveniently configure tmux, then I would like to leave you with some honorable mentions:

- [`gitmux`](https://github.com/arl/gitmux): a binary that you can simply download, configure, and execute in your `.tmux.conf`. No runtime dependencies needed.
- [`powerline`](https://github.com/powerline/powerline): a fully-featured statusline utility for vim, tmux, and more. Requires python.
- [`tmux-git`](https://github.com/shuber/tmux-git): a tmux plugin.

For more inspiration, feel free to browse my [dotfiles](https://github.com/pbnj/dotfiles).

Thank you for reading.

Happing hacking!