Image of git blame | How to Blame in Git

ADVERTISEMENT

Table of Contents

Introduction

Git blame is a command used to check which developer authored each line of a committed file and how many revisions it’s had. The output of Git blame displays a line-by-line readout of a file's content, indicating the line number, the most recent commit ID that changed the line, the author of the change, and the date and time of the change.

The idea is that the team can track changes to individual lines of code and attribute them to a commit and author if problems arise. Git blame does not reveal information about lines that have been deleted or replaced.

When to Use Git Blame

Git blame can reveal who last changed a line of code and when they changed it.

Git blame is a great tracking tool for teams. Unexpected errors can be introduced in many ways and at many points in the development process. Because of the distributed and collaborative nature of Git version control, it can be impossible to keep track of who made what changes. That’s where git blame can step in to help.

How Do You Use Git Blame

Most use cases of Git blame center around an error or bug introduced by someone working on the project, making changes and commits.

When you realize your project has a bug because something isn't working correctly, you need to identify the problematic commit before you can figure out who introduced it.

Start by using git bisect to track down the commit that introduced the bug. Git bisect uses a binary search algorithm to efficiently search through commits, halving the potential commits with each bisect. To get started enter git bisect start.

Next, enter the last known good commit and the known bad commit (usually HEAD) as follows:

git bisect bad <commit hash> 
git bisect good <commit hash>

Git will begin bisecting. You’ll need to test your project after bisect checks out each commit, to verify if it's good or bad. The process will continue until there are no commits left to verify. Then Git will output:

<commit hash> is the first bad commit

Once the commit that introduced the bug has been identified, the commit needs to be checked out using git checkout <commit hash>. From that point you can use git diff HEAD^ HEAD to compare the changes made to that commit from the previous commit.

There may be multiple authors that made changes to the same commit. Looking through the git diff output reveals what was removed or added for each line. To get started plug the last known good commit hash and the bad commit hash that you found with git bisect, into the git diff command:

$ git diff <good commit hash> <bad commit hash>

Examine the output to figure out which lines introduced the bug.

Now that you’ve narrowed down the specific bad commit and located which lines were last edited, it’s time to use git blame to identify who made the changes for the lines that introduced the error. The basic git blame command format is as follows:

git blame <filename>

The default git blame output format displays the commit hash, author name, date and time, line number, and line content in the following format:

Commit Hash (Author name Date Time Line Number) commit message

Here is an example with this format filled in with dummy data:

1a2bc34d  (Jane Doe 2022-02-02  01:11:11 -0800 1) this is an example

In the example below, we’re looking at a basic Python calculator program and calling git blame to look at the revision history. Remember that this is a line-by-line output of each revision commit hash, author, timestamp, line number, and code change.

In this example, you’ll notice multiple people are working to create a calculator, but someone introduces a bug that causes the calculator to malfunction:

$ git blame calculator.py

0a2012f  (John Doe  2022-05-05  10:23:10 +0100 1) # program makes a simple calc
85c0354 (John Doe    2022-05-06  01:20:10 +0100 2) # function for adding 2 num
85c0354 (Tom Train   2022-05-06  05:30:20 +0100 3) def add (x, y):
85c0354 (Tom Train   2022-05-06  08:45:05 +0100 4) 	return x + y
85c0354 (John Doe   2022-05-06  08:49:32 +0100 5) # function for subtracting 2 num
cd918fd (Jane Smith  2022-05-08  10:15:10 +0100 6) def subtract (x, y):
cd918fd (Jane Smith  2022-05-08  11:00:20 +0100 7) 	return x + y
cd918fd (John Doe     2022-05-10  08:40:50 +0100 8) # function for multiplying 2 num

Let's assume you've already identified the problematic commit to be 85c0354... by using git bisect. From git diff, you know that someone coded the subtraction function in lines (6)-(7) to add instead of subtracting.

In the git blame output above, you can see that Jane Smith was the original author that coded this function. This is a simple example of a very obvious error, demonstrating how git blame can help your team.

Git Blame Options

To preview the git blame command options, just type in git blame with no file extension or modifiers, or you can use the git help blame command. There’s a wide range of options, but we’ll cover the most commonly used below:

  • git blame -w – Simplifies output, so whitespace changes made by an author aren’t listed in the revisions
  • git blame -c – Identifies lines that are copied from other files and displays the original author metadata
  • git blame -e – Instead of displaying the author’s username, the email address is displayed
  • git blame -m – Identifies lines that have been moved or copied from within the same file. The original author is reported, not the author that relocated that line.
  • git blame -l – Will display commit hashes at full-length
  • git blame -t – Displays time and date as a timestamp instead of the default date and time format.

Specifying Ranges with Git Blame

Instead of viewing the Git blame output for every line in a particular commit, you can precisely specify which lines you want to see. To do this, input the range of lines you wish to see along with the filename:

git blame -L 40,60 <filename>

Git Blame Porcelain Output Format Vs. Default Output

In Git, the term porcelain refers to user commands that produce human-readable output that is not intended to be parsed by scripts. The reason is that there is no guarantee for Git porcelain command output to stay the same over time. Because of this, porcelain commands are not stable enough to rely on for scripting purposes.

However, Git also includes a set of plumbing commands. Plumbing refers to lower-level commands that are more stable and less likely to change, producing output more suitable for automation and scripting purposes.

Additionally, the porcelain format is designed to suppress duplicate information. For instance, when viewing two separate blame lines in the same commit, the commit details will only be displayed once.

git blame --porcelain <filename>

Here is some example output of running the porcelain version of git blame, which returns a more scriptable format:

6a9bf6107daf9257c14d1c8e1c9c0fde3a020acb 4 4 1
author John Doe
author-mail <johndoe@mail.com>
author-time 1651002607
author-tz -0400
committer John Doe
committer-mail <johndoe@mail.com>
committer-time 1651002607
committer-tz -0400
summary <commit message here>
previous 8a5f7795129bcbf68d83aa82cb708de5a896882a index.html
filename index.html
*file content goes here*

Git Blame Vs. Git Log

Git blame is ideal when you want to examine individual lines in a specific file, whereas Git log is useful when you want to review the commit history of the repository.

With git blame, you can easily identify the last person to alter a line of code. However, if you need information related to branching, merging, or the evolution of the repository commit history, git log is the way to go.

Summary

Git blame is a simple, yet valuable command for tracking commit changes that may have multiple authors. Thankfully it’s easy to use and won’t introduce any issues or unexpected changes in your files.

Sometimes you need to identify the person who introduced a specific bug, which is why it is called git blame. It’s really not meant to be a punitive tool, but it can help the team provide support to developers or ask questions about what the intention of that line of code was supposed to be.

Next Steps

If you're interested in learning more about how Git works under the hood, check out our Baby Git Guidebook for Developers, which dives into Git's code in an accessible way. We wrote it for curious developers to learn how Git works at the code level. To do this we documented the first version of Git's code and discuss it in detail.

We hope you enjoyed this post! Feel free to shoot me an email at jacob@initialcommit.io with any questions or comments.

Final Notes