Learning Objectives
By the end of this lesson you will be able to:
- Read every column of
git blameoutput - Narrow blame to the exact lines you care about
- Follow a blame result through to the full commit
- Use blame as a question-finding tool rather than a fault-finding one
The Question It Answers
Your login test fails. The selector #login-btn finds nothing. The button is clearly on the page, so someone changed something.
git blame src/views/LoginView.js
8f3c2a1d (Marta Kovalenko 2026-07-14 11:23:07 +0300 41) const LOGIN_BUTTON_ID = 'login-btn-v2';
1a2b3c4d (Ivan Petrenko 2026-03-02 09:41:15 +0200 42) const FORM_SELECTOR = '.auth-form';
8f3c2a1d (Marta Kovalenko 2026-07-14 11:23:07 +0300 43) const SUBMIT_TIMEOUT = 5000;
Line 41 changed on 14 July, in commit 8f3c2a1d, authored by Marta Kovalenko. The ID became login-btn-v2. Your test looks for login-btn. That is your bug report, found in one command.
Reading the Columns
| Column | Content |
|---|---|
8f3c2a1d |
Abbreviated commit ID — the last commit to touch this line |
Marta Kovalenko |
Author of that commit |
2026-07-14 11:23:07 +0300 |
When that commit was authored |
41) |
Current line number in the file |
| the rest | The line's content |
The crucial word is "last". Blame shows the most recent commit that modified each line, not the commit that originally introduced it. A line rewritten five times shows only the fifth. Lesson 5.3's pickaxe search is how you find the first.
Narrowing the Output
A 900-line file produces 900 lines of output. Don't read them.
git blame -L 38,45 src/views/LoginView.js
Lines 38 to 45 only. This is the flag you will use every time.
git blame -L 41,+5 src/views/LoginView.js # line 41 and the next 5
git blame -L '/LOGIN_BUTTON_ID/',+3 src/views/LoginView.js # from a regex match
That last form is genuinely useful when you know the symbol but not the line number.
Two more flags worth knowing:
git blame -w src/views/LoginView.js
Ignores whitespace-only changes, so a reformat doesn't claim every line in the file. Almost always what you want.
git blame --date=short src/views/LoginView.js
2026-07-14 instead of the full timestamp. Much easier to scan.
A combination worth aliasing:
git config --global alias.who "blame -w --date=short"
From a Line to the Whole Story
Blame gives you a commit ID. That is the start, not the end.
git show 8f3c2a1d
The full commit: message, author, date, and every file it changed. Very often the message answers your question outright — "Rename login button ID for the new auth flow (PAY-4102)" tells you this was deliberate and gives you a ticket to read.
git log -1 --format="%H%n%an <%ae>%n%ad%n%n%B" 8f3c2a1d
Just the metadata and full message, without the diff.
git branch --contains 8f3c2a1d
git tag --contains 8f3c2a1d
Which branches and releases have this change — that is, whether it is already in production or still only on a feature branch. For a tester triaging a report from a customer, that is often the most important fact of all.
On the Word "Blame"
The command is badly named. What it produces is a name to ask, not a name to accuse.
The change on line 41 was almost certainly intentional and correct — a deliberate rename as part of a new auth flow. The defect is that the test was not updated with it. That is a process finding, not a personal one, and it is worth writing up that way.
The best outcome of a blame investigation is usually not a bug report at all. It is a two-minute conversation:
"Hey Marta — I see
login-btnbecamelogin-btn-v2in 8f3c2a1. Is the old ID gone for good, or is it still used anywhere? I need to update the auth suite."
Thirty seconds to write. Saves an afternoon of guessing.
Pro Tip: Most IDEs and GitHub's file view have blame built in, usually as "Annotate" or a "Blame" button. They show the same data with clickable commits. Use them for exploring; use the command line when you need
-L,-w, or a result you can paste into a ticket.
Key Takeaways
git blame <file>shows the last commit to touch each line, with author and date-L 38,45narrows the output to the lines you actually care about-wignores whitespace-only changes so reformats don't mask the real authorgit show <commit>turns a blame result into the full story, including the messagegit branch --contains/git tag --containstell you whether the change is live yet- Blame produces someone to ask, not someone to blame — the two-minute conversation is the point