Retracing a project’s state with git

Imagine, you’re coming back to a project that has advanced by two months with various people coming and going. And it’s your job to figure it all out. Git has your back! Here’s how.

So, there sure are a lot of branches. After a git fetch, you may want to start off with this one:

Where were the most recent changes made?

$ git for-each-ref --sort="-authordate:iso8601" --format=" %(authordate:relative)%09%(refname:short)" refs/remotes/origin
  22 hours ago   origin/topic/ipad
  34 hours ago   origin/topic/ipad-mini
  34 hours ago   origin/master
  2 days ago     origin/topic/2015-motoren
  8 days ago     origin/topic/mobile
  8 days ago     origin/topic/android
  4 months ago   origin/topic/2015-motoren-delhi

Based on this StackOverflow Answer. We’re going over the refs in refs/remotes/origin which basically means “the branches of remote origin” We’re printing those branches with relative date, but sorting them by iso date.

You get a good idea, what branches have changed recently. No need to dig into a branch that hasn’t changed in four months.

Who was working on those branches anyway?

You might be tempted to answer this question with git log, but that gets you output like the following snippet, and i’ll show you a better way!

$ git log origin/topic/2015-motoren
commit eff2017d61dar0659f43b0dv79ad5f1f13bd85e0
Author: Alice <alice@example.com>
Date:   Wed Sep 2 10:47:17 2015 +0200
    amazing stuff

commit 5af113f3es3f2981586b25e00806fe4d91ccb733
Author: Alice <alice@example.com>
Date:   Wed Sep 2 10:39:54 2015 +0200
    preparing amazing stuff

Looks like a lot of amazing stuff happened. And we also see, who’s involved. The git log command is powerful, and I use it a lot, but for the currenct question, it’s not the right tool. A nicer variation is the git shortlog:

$ git shortlog -s -n --no-merges "origin/topic/2015-motoren@{2 months ago}"..origin/topic/2015-motoren --
    19  Alice
     2  Bob

We get a nice list of people. -s is for “summary” which prints only the name (try without the -s, that’s also highly useful!), and the -n sorty by commit number. For this list, I also like --no-merges as those usually don’t introduce new code. We’re finishing it off with a commit-range that contains a relative date. We’re asking git for a commit 2 months in the past with @{2 months ago}.

So, what changed in general?

I’m still in a stage where i want a very broad overview, so i’ll ask git to tell me which files changed. Again, here’s the command first, and then an explanation:

$ git diff --stat -w origin/topic/2015-motoren@{2 months ago}..origin/topic/2015-motoren -- . ":!config" ":!vendor"
 .gitignore                                         |  6 ++
 Gemfile.lock                                       | 37 +++-------
 README.md                                          |  0
...
 42 files changed, 260 insertions(+), 313 deletions(-)

--stat is one of my favourite modifiers. It works on git log, too! It will print this list of filenames with the +/- summary. -w ignores whitespace changes. I’m not interested in those, they may well be the result of a badly configured editor or a refactoring. Usually that’s not what I’m looking for. Then we specify a range of commits again.

Some areas may not interest you at all. We have a project setup where a set of generated files get checked in (we have a good reason for it!), and they change frequently but are of no consequence. I’ll ignore those paths, too. This is done by telling git that only paths follow with two dashes: --. After that we need a base, which is . and then we can exclude all the things that clutter up the output. Here, it’s config and vendor. So i’ll add ":!config" ":!vendor" at the end. :! in front of a path means “exclude this”.

A quick glance at specific files

At this point, maybe you want quick confirmation that certain configuration items are as expected. You could checkout a branch, or you could just look at the file directly! In our example, we’re looking at a Gemfile, which lists all the dependencies of a project.

$ git show origin/topic/2015-motoren:Gemfile
source 'https://rubygems.org'

gem 'rake'
# and so on

We’re telling git show to pull up a file Gemfile, referenced by a ref origin/topic/2015-motoren. This is separated by a colon. The command is very fast, and you don’t need to change your current working tree!

Ready to pull!

There’s an almost infinite amount of possibilities in gits commands. It’s sometimes hard to tell from the manual, what a real-world application might be. I encourage everyone to curate a list of their favourite combinations. If you have another question or a simpler answer, please share them in the comments!


Leave a Reply


Author

Claudius Coenen is a tech-enthusiast. He's writing on all kinds of topics, including programming, technology, gadgets and media.

This site features his occasional articles, findings, documentations.

Categories

Connect