git blame | How to Blame in Git
Table of Contents
- When to Use Git Blame
- How Do You Use Git Blame
- Git Blame Options
- Specifying Ranges with Git Blame
- Git Blame Porcelain Output Format Vs. Default Output
- Git Blame Vs. Git Log
- Next Steps
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 <firstname.lastname@example.org> author-time 1651002607 author-tz -0400 committer John Doe committer-mail <email@example.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.
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.
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 firstname.lastname@example.org with any questions or comments.
Recommended product: Git Guidebook for Developers