Git Aliases for the Lazy and Grug Brained

󰃭 2024-10-09

I’ll admit that I am lazy, have a terrible memory and generally fit the archetype of the grug brained developer. As such I endeavour to make my life as easy as possible, ideally with as little effort as possible. Usually this manifests as me doing some work up front to make my life easier later on, and in fact this has turned out to be a corner stone of my my career to some extent, essentially automating myself out of a job is my job (or at least a good part of it).

With that in mind, lets take a look at git aliases and how they can empower the laziest of engineers.

I use git most days and usually I use it via the cli, I am no git ninja, merely competent at best and I am not cli zealot but these days that is usually where I am most comfortable. I occasionally hop into LazyGit or some GUI tool if I end up in a nasty rebase or merge, but most of the time I am happy using the plain ole git command. But there are things that I have found myself typing over and over and that never sits well with me. A waste of time and a waste of keystrokes (even with completions). In addition to that, I found myself forgetting the syntax for some of the more complex commands that I might not use every day but want to have at hand when I need them.

To help address both these issues I have a gathered a collection of git aliases over the course of several years. If I find I need to googled the same git command more than once or twice, then that is a prime candidate for an alias. I can’t take credit for all of these aliases, I have borrowed and stolen them from various places on the internet, (as any good and lazy engineer would do) and I have modified them to suit my needs, as should you.

Before I get into the actual git aliases, it is worth mentioning that I also alias git to g in my shell (see, I really am very lazy). I use zsh and have the following in my .zsh_aliases file (which I source in my .zshrc:

alias g='git'

One day I may do a post on my zsh aliases, but for now lets try and stay on task, so without any further ado here are my git aliases in all their glory with brief descriptions, as taken from my ~/.gitconfig file (note the second entry la = list-aliases requires a helper bash script, keep reading to the end for details on that and why it is important):

[alias]
  # List all aliases
  laa = "!git config -l | grep alias | cut -c 7-"

  # List all aliases with descriptions (requires 'git-list-aliases.sh' script)
  la = list-aliases

  # Shorthand for 'git add'. Adds files to the staging area.
  a = add

  # Adds all changes (tracked and untracked files) to the staging area.
  aa = add -A

  # Shorthand for 'git branch'. Shows or manages branches.
  br = branch

  # Shorthand for 'git checkout'. Switches between branches or restores working tree files.
  co = checkout

  # Shorthand for 'git commit'. Records changes to the repository.
  ci = commit

  # Commits all tracked changes without needing to 'git add' first.
  ca = commit -a

  # Shorthand for 'git status'. Shows the current state of the working directory and staging area.
  st = status

  # Shorthand for 'git pull'. Fetches from and integrates with another repository or branch.
  pl = pull

  # Pulls changes but replays your local changes on top, rather than merging.
  pr = pull --rebase

  # Shorthand for 'git push'. Pushes commits to the remote repository.
  pu = push

  # Resets the current branch to a specified state, discarding all changes.
  rh = reset --hard

  # Restores working directory files to their last committed state.
  rs = restore --

  # Displays a log of commits in a formatted view, showing commit hash, date, message, and author.
  hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short

  # Displays the type of a Git object (e.g., commit, tree, blob).
  type = cat-file -t

  # Shows the content of a Git object (e.g., commit, tree, blob).
  dump = cat-file -p

  # Displays a compact, oneline log showing the commit hash, message, and author, with a graphical representation.
  l = log --graph --pretty=format':%C(yellow)%h%C(auto)%d%Creset %Creset%s %C(242)<%an>%Creset'

  # Displays a compact, oneline log including relative dates (e.g., '2 days ago') along with commit details.
  ll = log --graph --pretty=format':%C(yellow)%h%C(auto)%d%Creset %Creset%s %C(dim 11)(%ar) %C(246)<%an>%Creset'

  # Shows a log with statistics about the changes in each commit, excluding merge commits.
  ls = log --pretty=format':%C(yellow)%h%C(auto)%d%Creset %Creset%s %C(242)<%an>%Creset' --stat --no-merges

  # Displays the name of the current branch.
  cb = rev-parse --abbrev-ref HEAD

  # Finds and displays the parent branch of the current branch.
  pb = !"git show-branch -a | ack '\\*' | ack -v \"`git cb`\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//'"

  # Shows the most recent tag in the current branch.
  lt = describe --tags --abbrev=0

  # Displays a list of filenames that have changed between commits or in the working directory.
  filediff = diff --name-only

  # Shows the details of the most recent commit (oneline log).
  last = log -1 HEAD

  # Prepares a commit to be squashed with a previous one during a rebase.
  fixup = commit --fixup

  # Reverts the last commit, keeping the changes in the working directory.
  undo = reset HEAD~1 --mixed

  # Removes files from the staging area (undoes 'git add') but leaves the changes in the working directory.
  unstage = reset HEAD --

  # Lists all tags in the repository.
  tags = tag -l

  # Lists all branches, both local and remote.
  branches = branch -a

  # Lists all remote repositories with their URLs.
  remotes = remote -v

  # Deletes all local branches that have been merged into the specified branch (default is 'main').
  bclean = "!f() { git branch --merged ${1-main} | grep -v \" ${1-main}$\" | xargs -r git branch -d; }; f"

  # Deletes all local branches that have been merged into the specified branch (default is 'master').
  bclean-old = "!f() { git branch --merged ${1-master} | grep -v \" ${1-master}$\" | xargs -r git branch -d; }; f"

Helping yourself to help yourself

Although it is possible to list out all of your git aliases with git config -l | grep alias | cut -c 7-, it is not very readable, you don’t get the descriptions of the aliases, and it is not very user-friendly to the forgetful among us, so of course I added an alias for that too. The following script is a git ‘plugin’ that I use to list all of my git aliases with their descriptions. (Any script in your path that starts with git- can be run as a git command.) I have this script saved as git-list-aliases.sh in my ~/.local/bin directory and I have added that directory to my PATH. I can run git list-aliases.sh to list all of my git aliases with their descriptions. Of course I then make an alias for that too, la in my .gitconfig file, so I can use git la to get a quick look at all aliases I have configured.

The script is as follows:

#!/bin/bash

# Path to user's .gitconfig (adjust if needed)
GITCONFIG="$HOME/.gitconfig"

# Function to list Git aliases from .gitconfig
function list_git_aliases_with_comments {
    awk '
    BEGIN { inside_alias_section = 0 }

    # Look for the [alias] section
    /^\[alias\]/ { inside_alias_section = 1; next }

    # If inside the alias section, print lines until another section starts
    /^\[/ { inside_alias_section = 0 }

    # Print lines in the alias section
    inside_alias_section { print }
    ' "$GITCONFIG"
}

# Run the function
list_git_aliases_with_comments

To integrate this script into your git aliases, follow these steps:

  1. Save this script as git-list-aliases.sh in a directory within your $PATH, for example ~/.local/bin/git-list-aliases
  2. Make it executable:
chmod +x ~/.local/bin/git-list-aliases
  1. Add the git ls alias to your .gitconfig:
[alias]
  ls = "list-aliases"