Useful Git aliases

Posted on

In what’s apparently turning into a series of posts about how I use Git, I thought I might post a few of the aliases I use. Adding aliases to Git effectively allows you to define your own simple sub-commands, which invoke one of the built in sub-commands, another alias, or some external command.

I’ll start with a quick run down of how to create aliases, but if you’re already familiar with that then you should skip ahead to my aliases.

Creating aliases

As with all Git configuration, you can create aliases from the command line with the git config command or modify the configuration files directly.

To create an alias from the command line you use:

git config --global alias.foo 'status --short'

This will create a global alias foo such that git foo is now the equivalent of git status --short. If the --global flag is omitted then the alias is only created for the current repository.

If you want the alias to run an external shell command, instead of a Git sub-command, then you prefix the alias with a !:

git conifg --global alias.bar !echo

You’ll also need this prefix if you want an alias that starts with a Git sub-command, but then pipes the output into some other program (there are some examples of this later).

To create the same aliases by editing the configuration files you would add the following lines:

[alias]
  foo = status --short
  bar = !echo

For a global alias this goes in ~/.gitconfig, and for a repository specific alias it goes in .git/config. I’ll use this format for the examples that follow.

When you use your aliases, any command line arguments you provide will be passed on to the aliased command. For example, with the aliases configured above git foo --branch is the same as git status --short --branch.

A few of my favourite aliases

Pretty graphs

[alias]
  graph = log --all --graph --decorate --oneline -n30

This alias shows the last 30 commits from all branches laid out in a graph, and decorated with branch and tag names. If git log gets more than one -n parameter it will use the last one, which means you can easily change the number of commits shown in the graph when you want more or less context (e.g. git graph -n5).

I used to use GitX to visualise the commit graph, but I was usually trying to quickly get my bearings before I issued another command, so having the graph in my terminal to refer back to is more useful than switching away to another app to see it (I have my core.pager set to cat, so Git doesn’t pipe everything into less and the output stays visible when I start typing the next command Correction: As Matthew Somerville pointed out in the comments, the default pager is less -FRSX, which means the output is still visible after quitting less).

Seeing where I’m up to

[alias]
  cb = !git branch | grep ^* | cut -d' ' -f2
  sb = !ls .git/refs/remotes/*/$(git cb) | cut -d/ -f4,5 | \
       xargs git show-branch $(git cb)

These two commands work together to show the differences between my currently checked out branch (found by git cb), and the branches with the same name on all remotes. For example, if I have the master branch checked out in a repository with remotes called heroku and github, git sb is the (much shorter) equivalent of git show-branch master heroku/master github/master.

Rather than using git pull I prefer to use git fetch and then manually merge or rebase my changes. I find the time between fetching and merging very useful: I can see what other developers have been working on, spot potential conflicts, and generally keep up with what’s changing in the codebase. My git sb alias gives me a quick overview of the changes with a single command.

Incidentally, if you’ve not used git show-branch I’d definitely recommend trying it out. It’s become one of the Git sub-commands I use most often.

GitHub

I’m cheating a little here, this one started life as an alias but it got so complex that I re-wrote it as a Bash script. A handy feature of Git’s architecture is that any executable on your path with a name that starts with git- can be executed as a Git sub-command. In this case my file is called git-hub, so I can execute it by running git hub:

#!/bin/bash

github_remote=$(git remote -v | grep -Eo 'github.com[:/][^.]+' | head -1)
if [ -z $github_remote ]
then
    echo "No GitHub remote"
    exit
fi

github_url="https://${github_remote/://}/"
if [ ! -z $1 ]
then
    sha=$(git rev-parse $1)
    github_url="${github_url}commit/$sha"
fi

open $github_url

You can use this in two ways. Without any arguments (git hub) it will just open the GitHub page for the repository. When an argument is given it will attempt to convert that argument into a commit ID (using git rev-parse) and then open the GitHub page for that specific commit, for example git hub origin/master~3.

I find this very useful when combined with my git sb alias; when I’m reviewing new commits before I merge in my own changes I can easily open up a specific commit’s GitHub page to leave a comment or read in more detail later.

Finding things

[alias]
  rgrep = !git grep

This alias runs git grep from the root directory of the repository, so you can search the whole tree for something even if you’re currently in a subdirectory.

I wrote this one recently as an answer to a Stack Overflow question, so it’s not exactly one of my everyday tools, but it does demonstrate a useful property of aliases: Any alias to an external command (i.e. any alias that starts with !) is executed from the repository’s root directory regardless of the current working directory.

That’s all folks

I find these aliases make Git much more useful and enjoyable to use, hopefully you will too. You can find all of the examples in a Gist on GitHub for reference, easy copying and pasting, or suggested additions and improvements.

4 Comments

Matthew Somerville commented on :

"(I have my core.pager set to cat, so Git doesn’t pipe everything into less and the output stays visible when I start typing the next command)" - I thought git by default called less with -FRSX; certainly, I don't get anything disappearing when I hit q in default git, no special pager set.

You might want to investigate git symbolic-ref HEAD rather than parsing the output of git branch - something like "git symbolic-ref HEAD 2>/dev/null" and then strip off refs/heads/ or set to "detached HEAD" if no output.

And I'm sure you've seen this - http://www.jukie.net/bart/blog/pimping-out-git-log is what I use by default for my pretty graphs.

George Brocklehurst responded on :

Thanks Matthew.

I wasn't very clear about my pager settings; I was referring to the output disappearing after I'd hit q in less. Most of the time that isn't what I want, I'd still like to be able to glance up and see the output later.

Using symbolic-ref sounds simpler than parsing the branch output, I'll look into it.

Matthew Somerville commented on :

Obviously I haven't been clear either, as that's what I meant :-) No output disappears for me when I hit q with default git behaviour; it all stays there so I can see the output. This is because git calls less with -X which stops any page clearing your terminal might do with the te termcap. (You can set the LESS environment variable to the options you want less to use by default, too, so that it never happens with less.)

Philip Möjbro commented on :

Now I'm `cb`ing and `sb`ing like never before.