Oli.jp

Articles…

Git config powerup with aliases, diff & log

Git’s commands tend to have good defaults, but also a lot of customisability via flags. But all that typing, who needs it when we have git aliases?

Making a git alias via git config or .gitconfig

There are a couple of ways we can make an alias in git:

  • using the command git config alias
  • editing the .gitconfig file directly

While you can make aliases per project, I always make ’em global via git config --global alias or by editing ~/.gitconfig.

Here’s the pattern to make an alias using git config:

git config --global alias.alias command

For example, I use git status a lot, so a shorter alias would be nice:

git config --global alias.s status

This will add the following to your ~/.gitconfig file:

[alias]
  s = status

Now if I type git s I get the same output as git status. Of course you can always open ~/.gitconfig in a text editor and add s = status manually under the [alias] section. Here are some other basic aliases I’m using (more exciting ones to follow):

Some basic git command aliases
AliasCommand
git sgit status
git a!git add . && git status
git au!git add -u && git status
git aa!git add . && git add -u && git status
git cgit commit
git cmgit commit -m
git spullgit svn rebase
git spushgit svn dcommit

A couple of things to note:

  • If you’re using git config you’ll need to quote commands that are more than one word, e.g.
    • git config --global alias.c commit
    • git config --global alias.cm "commit -m"
    and escape some characters, e.g. for $ use \$
  • We can alias shell commands, so you can e.g. pipe git output to another tool. Do this by prefixing the whole command with “!” (example that includes shell script in the conclusion).
  • We can chain commands using “&&
  • If the command takes input, like the commit message for git commit -m, as long as -m is last you’re fine e.g. with the above aliases git cm "initial commit" is the same as git commit -m "initial commit"

Better history with git log

git log gives us access into git’s history, but for me the default is lacking.

Example output for a commit from git log

The main info I want is:

  • an overview of commit messages to find a commit
  • the commit’s hash tag for using with git diff etc
  • what branch/repo a commit is on or from
  • what changed in each commit and by how much

Let’s fix that — aliases to the rescue!

git log history overview

Add this alias then try git l, ideally in a multi-user project with lots of branching and merging:

# command (this is why aliases rock!)
$ git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
# create alias via shell
$ git config --global alias.l "log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'"
# or add directly to ~/.gitconfig under [alias]:
l = log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'

You get an abbreviated commit hash (great for pasting into git diff etc), branch and remote info, the commit message, author and relative date, in a compact format. And it graphically shows branches via railway diagram craziness. ASCII-art FTW!

git log brings teh awesum

I originally used an overly colorful version, but this is based on Ben Hoskins’ one in Git for busy people: see what you’re doing.

git log detailed history

While the previous alias solved my first three needs, I still sometimes want to see what changed and by how much. This next command gives the same info as the default git log, but adds a list of each file changed per commit, and an indication of how much each file changed. I alias it to git ll.

# command
$ git log --stat --abbrev-commit
# create alias via shell
$ git config alias.ll log --stat --abbrev-commit
# or add directly to ~./gitconfig under [alias]
ll = log --stat --abbrev-commit
Indicating how each file changed in a commit — green pluses are insertions, red minuses are deletions

It’s handy for seeing which commits involved major changes or touched a lot of files.

Bonus: total commits, including per-author

This just tells you how many commits your repo has: git log -a --pretty=oneline | wc -l. You can also break total commits down by author using git shortlog -sn.

For more info on git log Git Immersion: History is worth a read.

Better diffs with git diff

I use git diff a lot, but the default setup has some problems:

  1. the default pager less doesn’t soft-wrap or scroll horizontally
  2. by default lines are compared, so small changes in a paragraph are hard to spot
Default git diff, with long lines being cut off because they’re not soft-wrapped (boo!)

We can improve on this with a couple of config tweaks. To add soft wrapping to git diffs we can add pager = less -r under [core] in your .gitconfig, e.g. by using git config --global core.pager less -r.

Changing the pager settings for a soft wrapped diff — getting better

To change from per-line to per-word diffs, we can use the flags --word-diff=color or --color-words. The easiest way is to make an alias like git config --global alias.d = diff --color-words.

Soft wrapping plus OMG THIS IS AWESOME --color-words

While --color-words automatically turns on diff coloring, I’ve also got the following in .gitconfig under [color]:

[color]
  ui = auto # covers diff = true, status = auto, branch = auto
  interactive = auto

There’s a lot more we can do with git diff — here’s some patterns I’ve found helpful:

git diff
Compare working copy to index (files prepped for committing via git add)
git diff head
Compare working copy to head (the most recent commit)
git diff [filename]
Compare a specific file (with path if necessary) to index
git diff --stat
Show insertion and deletion stats for each file with +-
git diff [commit] [filename]
Compare current [filename] to the same in a specific [commit] (via commit hash etc)
git diff [commit]:[old-name] [new-name]
Compare a renamed file
git diff [branch]..[other-branch]
Compare the most recent commits (tips) of two branches
git diff [branch]...[other-branch]
Compare the tip of other-branch and the closest ancestor (fork point) on [branch]
git diff [branch]:[filename] [other-branch]:filename
Compare two files on different branches
git diff --no-index [filename] [filename]
Compare any two files, even if they’re not in a repo :O

If terminal-based diff still doesn’t do it for you, try setting opendiff as your diff client.

Conclusion

Here’s my .gitconfig file as a gist for your forking pleasure.

I hope that’s given you some useful aliases, or at least some ideas to make your own. I’ll leave you with one last alias from Bernd Jünger to copy and paste into your ~/.gitconfig under [alias]:

alias = !git config --list | grep 'alias\\.' | sed 's/alias\\.\\([^=]*\\)=\\(.*\\)/\\1\\\t => \\2/' | sort

When you’re done it might come in handy ;)

If you have any feedback or comments, contact me via Twitter (@boblet) or Google+ (Oli Studholme).