Mastering Git Log

July 16, 2015
on
git

I have been using git for a number of years now and have accumulated some awesome git aliases. In this blog post I want to share some of my favourite git log aliases. The log command is probably my most used command, it lets me view the latest changes, compare changes between branches, view just fetches changes and examine changes other team members made.

For those of you that don't know, Git is a free and open-source distributed version control system. The git log command is used to display code changes in chronological order.

Basic Log Commands

Running the usual git log will give you a list of all commits in chronological
order. Use the usual vi bindings --gg, G, Ctrl-D, Ctrl-U-- to navigate swiftly
around the log.

View the latest changes with the -p flag--it stands for patch. This will
display all commits with patch information appended to the bottom of each one.
This is immensely useful for viewing the changes each commit introduced.

Most people don't know this, you can display the log of other branches by passing in a
branch name or a commit hash. Remember a branch name essentially is a pointer to
a hash.

git log dev
git log origin/dev

There are times when I want to view the changes a specific fix introduced but it happened maybe a week ago and is not easily accessible by scrolling. With the
--grep flag and the issue number you can find the log.

I made the alias lgr stands for log grep. I always prefix my log aliases with
an l to show it uses the log command.

lgr = !sh -c 'git l --grep=$1 --max-count=20' -

I have personally never used this command but am itching to try it out. It lets you see changes of a function over time--yeah not kidding. There are two
version of this command. One lets you specify a line range--which works well for
scripting languages-- and the other a regex. I found the regex works well in
C++.

git log -L :main:main.cpp

In both cases the file path has to be specified. You'll be amazed at what you
learn by stepping through a functions history.

Comparing Commits in Branches

Comparing branches is something I do on a daily basis. Did this branch get merged into master? How many commits is development ahead? Are common questions.

Say your team has been pushing commits to the dev branch for some time.
You know master is quite behind dev but you don't know by how much.
So you want to log of all the commits
in dev that master does not have.

This means log all commits reachable by dev that are not reachable by master.
You can also think of it as, ignore commits in master and display commits only
in dev.

So, you now know that dev has two commits that master does not have but,
master could have commits that dev does not have. What if you want to see commits
that are not reachable by both dev and master? This brings us to the triple dot
syntax.

First thing you should look at is the arrow, this shows which branch the commit
belongs to. The > is pointing to dev and < is pointing to master, the
arrow direction is relative to construction of the command. Reversing the
comparison will reverse the arrows. Hence the flag name--left-right-- master is
on the left, dev is on the right.

So what does this tell you? There are two commits inside dev that master doesn't
have and there is one commit--a hotfix--inside master which dev doesn't have. And you did this all
commandline--what a time saver.

Remember you can even add the -p flag to view the changes.

Seriously, remember these two syntaxes, I use these on a daily basis.

Moving on, the log command can even be used to preview merges. Say you been working on a feature
branch for some time. You can run this command to view the commits that have to
be merged in.

A git fetch fetches changes and puts them in the remote version of your
branch, in this case origin/master. You can then compare the remote
branch--origin/master--
with your local branch--master.

Or view the commits that just went in from a git pull or a git merge.

git log ORIG_HEAD.. --oneline
923c4ec Added something

ORIG_HEAD is the previous state of HEAD before it was changed by a command
like git merge or git rebase. You might notice there is no argument on the
right side--ORIG_HEAD..-- the right side will default to HEAD.

Understanding the Graph

I've shown most of the log commands that I use in my daily workflow, except
one--the graph flag. It gives you such a
nice overview of the branches history and the state of
other branches as well.

This graph tells us not only the recent commits in the branch but also nicely
displays the merges that took place. Two arrows pointing to an
asterisk means it was a merge commit--it brought two separate commits together
through a new commit, ie b9326fa.

So how is this useful? Being able to see merge commits and the commits they
integrate allows for better decision making. For example I wouldn't want to
interactively rebase ba40fbd because it'll lead to confusing conflicts, a
better approach would be to do a soft reset.

My Aliases

Here is a big list of my favourite log aliases, do to them as you wish.

This aliases improves the graph functionality by adding relative dates, name of
committer and branch names.

This alias has to be one of my favourites, it displays all commits on a single
line and displays file changes on their own line. I use this to quickly find
which files were modified to look for potential bugs or to pick up someone else's
work.