Improving git workflow
Tags: git, cli, productivity, fish
Published: 2023-07-06 11:58:58

---
title: Improving git workflow
published: true
date: 2019-04-30 16:45:00 UTC
tags: git, cli, productivity, fish
canonical_url: https://kirillmaltsev.net/blog/improving-git-workflow
---

Over the 8 years that I use git, I tried different GUIs and TUIs but nothing really stuck with me (I’ll list a few of them below anyway). Some of them had great UI but didn’t cover my whole git workflow. While others had a lot of commands the user experience wasn’t that great. So I always ended up in a terminal running some command because either it was faster or a git tool I was using at that moment hadn’t supported the needed command.

A couple of years ago I decided to go all in with git CLI and incrementally improve my workflow.

First I was thinking of making my config clean, adding comments, and publishing it to GitHub. But other people have other approaches to working with git, use different command line shells, and even have their own mnemonic rules for creating command shortcuts. So most developers can’t use my config out-of-the-box and would be required to tailor it (which few will do).

So instead, I decided to write a blog post, where I show you how you could incrementally improve your own git CLI workflow.

<!-- more -->

## Aliases

The most important part of improving the workflow is to avoid typing the full commands every time. Even if you complete just this part, you’d be much better off.

Your first task would be to create aliases for your most used commands. Here you’ve got two ways:

1. Use [git alias](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases).
2. Use aliases offered by your command line shell.

I don’t see any pros in using the first approach because it’d require you to type `git ` every time anyway, so in my examples, I’ll be using only the latter method.

Also in all my examples, I’ll be using bash shell (although I use [fish](https://fishshell.com/)) because I think it’d be easier for you to adapt my bash config examples to your shell than vice versa.

First I suggest you create aliases for basic commands like:

```bash
alias gs="git status"
alias gc="git commit"
alias gl="git log"
alias gp="git push"
alias gpl="git pull"
```

I prefer to use the first letter of each command’s word for an alias, so, for example, `git commit --amend` becomes `gca`. But you might have other mnemonic rules.

I also suggest you don’t try to create an alias for every possible command that you might use in the future. I tried doing that and just ended up not using most of them since

1. I actually didn’t use them a lot.
2. When I needed to use them, I just couldn’t remember the alias I choose.

After you get used to the aliases, you could start creating new aliases for more complex commands.

Here are a few that I use a lot:

```bash
# Amend and automatically commit staged changes to the latest commit
alias gcah="git commit --amend --reuse-message=HEAD"
# Commit staged changes with a temporary message
alias gcmt="git commit --message '$(date '+[ci skip] %Y-%m-%d %H:%M:%S')'"
# Interactively rebase all master’s commits that haven’t been pushed yet
alias grio="git rebase --interactive origin/master"
```

You can see [my full git config on GitHub](https://gist.github.com/maltsev/80a0aedcacf09c23aeaea779892c1eeb).

## Make commands interactive

Working with git involves selecting various entities a lot (e.g., a branch to merge, commits to rebase, files to stage, etc.). It’ll be nice to have a way to select them instead of typing them manually or copy-pasting them.

For that purpose, I use [fzf](https://github.com/junegunn/fzf), a CLI fuzzy finder. It’s a tool that reads a list from STDIN, lets you interactively select lines, and prints them to STDOUT. At first, it doesn’t make much sense nor does it look helpful. But combined with other commands it’d make your git workflow much smoother.

Let’s take one of the most ubiquitous git actions: selecting files to stage.

Here is what we usually do:

```bash
# List changed and new files
git status
# Stage some of them
git add foo/bar/a.txt foo/baz/new.txt
```

Typing the full file paths is tiresome. Let’s try to make it easier.

```bash
alias gas="\
    # Display all changed and new files
    git status --porcelain=v1 | \
    # Filter only those that haven’t been staged yet
    grep --invert-match --extended-regexp '^[MADR] ' | \
    # Then pipe these files to the fuzzy finder
    fzf \
        `# Use NUL instead of a newline char for line delimiter` \
        --print0 \
        `# Allow selecting multiple files` \
        --multi \
        `# Use exact match (instead of fuzzy)` \
        --exact \
        `# Display file changes in a preview window (you can scroll them with ⇧ Shift + ↑↓)` \
        --preview 'git diff --ignore-all-space --color -- {2} | tail -n +5' | \
    # Remove the status field from all selected files (the first 4 chars)
        # macOS comes with preinstalled BSD version of cut which lacks needed options,
        # So in case you’re a macOS user use gcut instead.
    cut --zero-terminated --characters=4- | \
    # And finally, use xargs to run git add with selected files
    xargs -0 git add -- \
"
```

Here is an example of how this function works:

{% embed https://asciinema.org/a/UfwxOtE8CQTnjaVWWEEfifEWx %} 

## Interactive rebase

git rebase lets you re-arrange, combine, and edit commits. It presents you with a commit list, which you have to edit manually in your text editor. It isn’t too convenient as well.

[git-interactive-rebase-tool](https://github.com/MitMaro/git-interactive-rebase-tool) is an interactive editor where you can re-arrange and pick commits for future actions just with a keystroke.

Here is an example of how it works:

{% embed https://asciinema.org/a/QSXck3N3De4ne62csFKJWnkte %}

## Git blame

I haven’t found a good way to make git blame interactive in a terminal yet. On rare occasions when I need it, I either use [tig](https://github.com/jonas/tig) or GitHub’s blame view.

I would appreciate it if you suggest some tools.

## Other tools

If you don’t want to cook up your own shell aliases and functions, you could look into the following nice tools. They didn’t work out for me but maybe would work for you.

- [tig](https://github.com/jonas/tig) — a TUI client which acts as a repository browser and presents you with different views for each git command (e.g., log, blame, tree). I still use it sometimes as interactive git blame.
- [lazygit](https://github.com/jesseduffield/lazygit) — another TUI client. I tested it for a while but didn’t get into it.
- [magit](https://magit.vc/) — a git porcelain for Emacs. The authors claim that it has a lot of features and could replace git CLI even for experienced users. Worth trying if you’re an Emacs user.

There are also a ton of GUI clients and plugins for various text editors. But I haven’t had much experience with them, so I can’t really recommend anything.

* * *

How does your git workflow look? Which tools do you use? I’d be interested to hear!