Searching through the Git history

5/12/17

Projects are growing over the years, code complexity can rise and the amount of classes in a OOP code base become more structured. For all the changes that happen in projects, developers are gladly using a Version Control System to track all the changes that are happening. Many of the open source projects are using Git and its advantages for their code, but I guess that this isn't any big news for you.

If you're working in a team, sometimes you'll have to look into the changes that happened over the last months and search for some specific revision or commit id, that introduced a new feature or bug. There are plenty of possibilities in Git to find what you're looking for in the commits, so here are a few commands I had to use regularly in the past and that can make your exploration through git log more efficient.

Commit messages


If you have to search through the commit messages, you probably already know how to use --grep.
$ git log --grep="phpunit 6"
commit 167392da3ca78d4f3dd2ed95694e6f678f174a59
Author: Claudio Zizza
Date:   Sun Feb 5 19:28:01 2017 +0100

    Update to phpunit 6
In case you know that there is a specific message in your git history, this will be the simplest way to find all the commits you're looking for. In this example, it means all commits, that have phpunit 6 in the commit message. But --grep can do much more for your search. In case you have two or more search terms, that have to be part in the commit message, you can combine those terms with --all-match and get all results where the messages contains both.
git log --grep="phpunit" --grep="Update" --all-match
commit 167392da3ca78d4f3dd2ed95694e6f678f174a59
Author: Claudio Zizza
Date:   Sun Feb 5 19:28:01 2017 +0100

    Update to phpunit 6

commit 9552d456fcac797b73e027ccbbefc72e23bc4f00
Author: Claudio Zizza
Date:   Wed Apr 13 23:59:21 2016 +0200

    Update phpunit to 5.3
If you omit this option, only one of the grep-terms have to be part of the commit message.

A merge is a commit too, so there may be some commits you don't want to be listed, even when they are part of the search term. For example, "Merge" can be a little bit tricky if it was also part of a regular commit for one of your features, when the default commit message of a merge starts with "Merge branch", but even for such a use case, git log provides a helpful option:
git log --grep="Merge" --no-merges
--no-merges doesn't list merge commits in your resulting log output and shows only the relevant ones from the feature development. Needless to say, that there's also the --merges option for only showing you the merge commits.

Of course, these options aren't for grep only, but can be used in combination with others of git log's options. A commit isn't just for their messages but also for the most important part: The code and its changes.

Code changes


It is possible to show only commits involving one or more files by appending the file paths at the end of your git log command. If you add the option --name-only, the output will also show which of the searched files were changed or added in the listed commits.
git log --name-only src/Exception/IntlFormatException.php src/Factory.php
Without the files in the command, --name-only lists all files, that are part of the commits. This can be quite handy when you need the history of a file and who had worked with it.

Sometimes much more information is needed by a developer when it comes to changes in a project. Like "show me every addition in the code, that involves the string IntlFormatException". In this example, IntlFormatException is a class name and we want to get all the changes, where this class was added. I usually use two different ways to get a list of commits where changes occurred:
git log -G IntlFormatException -p
git log -S IntlFormatException -p
Both, -S and -G can be used to search inside the history for changes, where the search term was involved in the code, added or deleted. With -G, you also have the full potential of Regular Expressions at your hand. In addition -p can be added to make the search result of the code changes visible in form of a diff for every listed commit.

Git log is much more powerful than what I've presented you here in simple commands and my most favourite one is still git log --help, because you will always be confronted with a use case, where you need the help of the Git documentation. I didn't even covered all the possibilities to format the list of commits, which can be handy from time to time and I hope that this little overview will be helpful next time you have to look through a Git history.


About Claudio Zizza
I'm working as a software developer for more than 15 years and used many coding languages and frameworks during that time, like PHP (of course), ASP, .NET, Javascript, Symfony, Laminas and more. I also contribute to the open source communities and am a part of the PHP Usergroup in Karlsruhe, Germany.
Follow me on Twitter (@SenseException)