skip to content

questions

16

What does git blame report for each line, and what can it not tell you?

level: juniorimportance: must knowfreq 60%

answer

  1. One commit per line, not many
  2. Last touched, not authored
  3. Narrow to a range first
  4. Re-blame from before that commit
  5. Deleted lines need a different mode

basics

~20 s

git blame annotates every line of a file with the commit that last modified it, plus that commit's author and date. It shows only the most recent touch, never the line's full history, and it says nothing about deleted lines.

solid answer

~50 s

`git blame <file>` prints the file with each line prefixed by the commit that **last changed** that line, its author and timestamp, and the line's number in that original commit. `-L 40,80 <file>` restricts it to a line range, and `-L :funcName:<file>` restricts it to a function. The key limitation is that blame answers "who touched this last", not "where did this line come from": a whitespace fix, a rename or a mass reformat becomes the answer for every line it touched. To go further back you re-blame from before that commit — `git blame <commit>^ -- <file>` — repeating until you reach a meaningful change. Blame also cannot show you a line that no longer exists; that requires `git blame --reverse` or a log-based search. Treat it as an archaeology tool for understanding code, not an accountability tool for assigning fault.

go deeper

for a junior

Know that blame annotates each line with the commit that last changed it, that -L narrows to a range, and that the result is a starting point you follow up with git show.

for a middle

Explain the last-touch limitation and demonstrate the drill-down loop with git blame <commit>^ -- <file>, plus -w for whitespace noise.

for a senior

Show that you know what blame cannot do — deleted lines, full line history — and reach for --reverse or a log-based approach instead of forcing blame to answer the wrong question.

for a principal

Connect it to practice: archaeology is only as good as the commit messages and the commit granularity a team enforces, so investment in message quality pays off years later during incidents.

## What blame computes `git blame <path>` walks history backwards from a starting revision (default `HEAD`) and, for every line currently in the file, determines the last commit that introduced or modified that line. The output prefixes each line with: - the abbreviated commit id, - the author's name, - the author timestamp, - the line number the line had in that commit, followed by the line's content. Useful presentation flags: `-s` suppresses the author and date for a compact view, `-e` shows email addresses instead of names, `-l` prints the full commit id, and `--date=short` changes timestamp formatting. `--porcelain` and `--line-porcelain` produce stable machine-readable output for tooling. ## Narrowing the question Blaming a two-thousand-line file is rarely useful. `-L` restricts the region: - `git blame -L 100,140 src/app.py` — lines 100 through 140. - `git blame -L 100,+20 src/app.py` — twenty lines starting at 100. - `git blame -L :parse_config:src/app.py` — the region Git recognizes as that function, using the language-aware function-name detection configured for the file type. You can pass `-L` more than once to blame several regions at a time. ## Starting somewhere other than HEAD `git blame <rev> -- <path>` blames the file as it existed at that revision. The important variant is `git blame <commit>^ -- <path>`: blame the file as of the commit *before* a given one. This is the manual drill-down loop. Blame a line, find that it points at commit X which is only a rename or a reformat, then re-run blame from `X^` to see who touched the line before X. Repeat until you reach the commit that actually created the logic. Experienced users do this by reflex; it is the single most useful blame technique after `-L`. ## What blame cannot answer 1. **The line's full history.** Blame reports one commit per line — the most recent. A line rewritten five times shows only the fifth. 2. **Deleted lines.** If the code you are looking for no longer exists, blame on the current file will never find it: blame starts from the lines that are there. `git blame --reverse <start>..<end> -- <path>` inverts the walk and reports, for each line, the commit in which it last existed — the way to find when something was removed. 3. **Why.** Blame gives you a commit id; the reasoning lives in the commit message, and in whatever discussion the message references. A blame result whose commit message is "fix" teaches you nothing, which is the practical argument for writing real commit messages. 4. **Intent versus mechanics.** A commit that reindented a whole file is the honest answer to "who last modified this line" and a useless answer to "who wrote this logic". Git provides explicit machinery to look past such commits. ## Blame is not blame The interviewer's framing matters here and candidates are frequently scored on it. Reaching for blame to identify who to hold responsible is a cultural red flag; reaching for it to understand *why* unfamiliar code looks the way it does — then reading the commit message and the surrounding change — is the professional use. The Git project itself offers `git annotate` as a synonym precisely because the name is loaded. ## Whitespace noise `git blame -w` ignores whitespace when deciding whether a line changed, so a reindentation stops shadowing the real author. Combined with the move- and copy-detection options and with an ignore-revs file for known formatting commits, `-w` is the first line of defence against archaeology that dead-ends in a formatting commit. ## Interactive alternatives Blame output is a starting point rather than a destination: once you have a commit id, `git show <commit>` gives you the whole change and its message, which is usually where the actual explanation lives. Many people run blame, note two or three commit ids, and spend most of their time in `git show` afterwards.

  • A blamed line points at a commit that only reindented the file. How do you find the real change?
    Re-run blame from before that commit: git blame <commit>^ -- <file>, optionally with -L for the same range. Repeat until you reach a commit that changed logic. Adding -w so whitespace-only edits stop counting as changes usually skips such commits in one step.
  • How do you find out when a line that no longer exists was deleted?
    Ordinary blame cannot, because it starts from lines that are present. git blame --reverse <old>..<new> -- <file> walks forward instead and reports, for each line, the last commit in which it still existed, which pinpoints the removal.
  • How do you blame only one function rather than the whole file?
    Use the function form of -L: git blame -L :functionName:path/to/file. Git uses its language-aware function-name detection to find the region, so you get just that function's lines. The numeric forms -L 100,140 and -L 100,+20 work the same way for arbitrary ranges.
  • Why do interviewers care how you frame the use of git blame?
    Because using it to assign fault is a culture problem, while using it to understand unfamiliar code is engineering. The expected framing is: find the commit, read its message and full diff with git show, and use that context to decide whether the code can safely change.

saying these in an interview costs you the question

  • Thinks blame shows a line's full history
  • Uses blame to assign fault for bugs
  • Expects blame to find deleted lines
  • Blames an entire large file at once
  • Stops at a reformatting commit and gives up

context

open as a page

What does git diff show by default, and how does git diff --staged differ?

level: juniorimportance: must knowfreq 85%

basics

~20 s

Plain git diff compares the working tree against the index, showing changes you have not staged yet. git diff --staged (identical to --cached) compares the index against HEAD, showing exactly what the next commit would contain.

open as a page

What do the git log flags --oneline, --graph, and --decorate each add to the output?

level: juniorimportance: must knowfreq 70%

basics

~20 s

In git log, --oneline prints one abbreviated-hash-plus-subject line per commit, --graph draws the commit DAG as ASCII art down the left margin, and --decorate appends the ref names — branches, tags, HEAD — that point at each commit.

open as a page

What does git show display for a commit, and how does it differ from git diff?

level: juniorimportance: should knowfreq 45%

basics

~20 s

git show prints one object: for a commit it prints the metadata and log message plus the patch against its first parent. git diff prints only a patch between two snapshots and never shows commit metadata.

open as a page

How do you make git blame skip a mass-reformatting commit?

level: middleimportance: should knowfreq 40%

basics

~20 s

List the reformatting commit's full id in a file and point Git at it: git blame --ignore-rev <sha>, or --ignore-revs-file <file>, or set blame.ignoreRevsFile so it applies automatically. Blamed lines are then attributed to the previous commit that touched them.

open as a page

In git blame, what do the -M and -C options change about the result?

level: middleimportance: should knowfreq 35%

basics

~20 s

Both stop a move from being reported as new authorship. git blame -M detects lines moved or copied within the same file, and -C additionally detects lines that came from other files changed in the same commit; repeating -C widens the search further.

open as a page

Which git diff options help you summarize or filter a very large diff?

level: middleimportance: should knowfreq 50%

basics

~20 s

Use --stat or --shortstat for a per-file summary, --name-only or --name-status to list touched paths, --diff-filter to keep only additions, deletions or renames, -w to hide whitespace-only noise, and --word-diff for prose where line diffs read badly.

open as a page

In git diff, what does A...B compare that A..B does not?

level: middleimportance: should knowfreq 55%

basics

~20 s

git diff A..B compares the two commits' trees directly, identical to git diff A B. git diff A...B compares the merge base of A and B against B, so it shows only what B added, ignoring changes made on A since they diverged.

open as a page

In git log, how do you filter commits by author, message text, and date range?

level: middleimportance: should knowfreq 46%

basics

~10 s

git log --author=<pattern> matches the author header, --grep=<pattern> matches the commit message, and --since/--until bound the date range. Patterns are regular expressions; multiple --grep options are OR-ed unless you add --all-match.

open as a page

In git log, what does a trailing -- <path> limit, and what does --follow add?

level: middleimportance: should knowfreq 50%

basics

~20 s

A trailing pathspec limits git log to commits that changed matching files, and the -- separator disambiguates paths from revision names. --follow additionally continues the history of a single file across renames, using per-commit rename detection.

open as a page

When would git log -L beat git blame for tracing one function's history?

level: seniorimportance: should knowfreq 30%

basics

~20 s

git blame gives one commit per line — the last to touch it. git log -L 20,40:file.py walks the whole history of that line range and prints every commit that changed it, with its patch, so you see the code's evolution rather than a single snapshot of authorship.

open as a page

How do you find the commit that introduced or removed a specific string with git log?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Use the pickaxe: git log -S'<string>' lists commits where the number of occurrences of that string changed, so the commits that added or deleted it surface. git log -G'<regex>' instead matches any added or removed line against a regular expression.

open as a page

What does git shortlog -sn report, and when would you use it?

level: juniorimportance: nice to knowfreq 24%

basics

~20 s

git shortlog groups commits by author. With -s it prints only counts instead of subjects, and -n sorts by descending count, so git shortlog -sn is a per-author commit tally; add a revision range to scope it to a release.

open as a page

In Git, how do you search file contents as they existed at an older commit?

level: middleimportance: nice to knowfreq 25%

basics

~20 s

Pass the revision to git grep: git grep <pattern> <rev> searches the files recorded in that commit's tree without checking anything out. Output lines are prefixed rev:path:line so you can see where each match lives.

open as a page

What do Git's histogram and patience diff algorithms do that the default does not?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

Both anchor the diff on lines that appear rarely, so hunks line up with meaningful code instead of sliding onto common lines like closing braces. Git's default is Myers; select others with git diff --histogram, --patience, or the diff.algorithm config key.

open as a page

What does git range-diff show, and when is it the right tool?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

git range-diff compares two versions of the same patch series — typically a branch before and after a rebase or rewrite — pairing up commits and showing a diff of their diffs, so you can see what actually changed between iterations.

open as a page