Find All Issues Referenced in Commit Messages

Posted on Mar 30, 2014

Software is constantly changing. Bugs are fixed, features are added, performance is increased, and finally binaries are built. With this constant cycle of change come people wanting to know exactly what the changes are. Between major versions, and minor versions, we normally have release notes to give us this information. However, between release builds the list of items is in constant flux with no let up in the people wanting to know what the changes are. So, how do we fill these requests? How can we tell what issues have been addressed between two arbitrary branches? 1

For our purposes, we'll try to see what changed between Release/2.1 and RC/2.1/Candidate-8. Let's start by examining the commit log.

git log RC/2.1/Candidate-8
commit 4e1a63c733507921ff7be480084106816a37c9fc
Author: John Doe <jdoe@example.com>
Date:   Fri May 17 13:49:14 2013 -0500

    OW-397: Added export functionality to the UI.
...

Now things are looking good: the log messages follow a defined format: “PROJECT-NUMBER: Brief description of the commit.” If we modify the command slightly, we can filter the results to only show log entries that exist in one branch that dont exist in the other.

git log origin/Release/2.1...origin/RC/2.1/Candidate-8
commit 4e1a63c733507921ff7be480084106816a37c9fc
Author: John Doe <jdoe@example.com>
Date:   Fri May 17 13:49:14 2013 -0500

    OW-397: Added export functionality to the UI.

commit 779e41d3881703a1f8ada527de5fbcc29dd1bba0
Author: John Smith <jsmith@example.com>
Date:   Wed May 15 15:38:40 2013 -0500

    OW-404: Reflect changes to the model in the sidebar.

This is great information for a human and follows a well defined format, but it isn't really kind to parsers. We can fix this by adding the argument --oneline to git log.

git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --oneline
4e1a63c OW-397: Added export functionality to the UI.
779e41d OW-404: Reflect changes to the model in the sidebar.

This new output always follows the format “hash, space, issue id, colon, message”. Thus, the issue number will always be the first string matching “alphanum-num” after the hash. This can be expressed with the regex “^[A-F0-9]+ [A-Z0-9]+-[0-9]+”.

At this point, we're going to call on another tool from our command line arsenal: grep. 2 Grep will take an input stream, allow us to search it with a pattern, and return matches to us. Normally grep performs a simple substring search and returns the entire line if there is a match. We're going to modify this behavior a bit by passing grep -i -o -E. The arguments tell it to ignore case, display only the matched portion of the line, and that we want to use a regex for parsing.

git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
     grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+"
4e1a63c OW-397
779e41d OW-404

Each line now follows the pattern “hash project-number”. We can trim this down even more by passing each line to awk. We'll split each line on space and then take the second item by passing each line to awk -F " " ‘{print $2}'.

git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
     grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+" | awk -F" " '{print $2}'
OW-397
OW-404

At this point it looks like we've got the results that we want, with one important exception: duplicates. Since we're looking at each line individually, we'll see one mention for an issue in every commit it appears in. We'll finish up by cleaning the list with sort and uniq. This will sort all of the issues and then prune any consecutive duplicates from our list.

At this point, we have a quick little script to list all of the issues addressed between two commits.

git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
     grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+" | awk -F" " '{print $2}' | sort | uniq

Footnotes


  1. Ideally the issue tracker would be fully authoritative, but sometimes that just isn't the case. Someone closes an issue prematurely or forgets to close it entirely. That, however, is an issue for another post. ↩︎

  2. All of the tools that we use in this post come preinstalled on Linux and Mac. On Windows they are provided with MSysGit, though they can be installed manually through Cygwin if desired. ↩︎