Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

Git Blame: Trace Line-Level Provenance

Trace current file lines to revisions and authors, follow moved or copied lines, control history traversal, ignore mechanical revisions, and use machine-readable attribution output.

Levels: Advanced ~35 min read

Advanced

Learner goal

By the end of this lesson, you should be able to use `git blame` to identify which revision last modified lines, restrict attribution to a line range or revision range, follow moved or copied lines, understand merge traversal choices, ignore known mechanical revisions, inspect machine-readable output, and use reverse or alternate-content attribution when the investigation requires it.

What `git blame` tells you

`git blame` annotates each line of a file with information from the revision that last modified that line. The default output includes an abbreviated object name, author identity/date, and line-number information before the line content. It is an attribution tool for the current file contents, not a report of deleted or replaced lines.

bash
git blame src/example.txt

Quick check

What is the primary purpose of `git blame`?

Use a disposable repository containing a file changed by several commits.git blame file.txt

Restrict attribution to lines

Use `-L` to limit annotation to a requested line range. The option can also use a function-name form or regular-expression boundaries, which is useful when a file is large and only one logical region matters.

bash
git blame -L 20,40 src/example.txt
git blame -L '/^function example\(\)/,/^}$/' src/example.txt

Quick check

What does `-L 20,40` do?

Create a file with at least 40 lines.git blame -L 20,40 file.txt

Start from a revision or revision range

A revision argument changes the point from which attribution begins. Revision-range and date limits can restrict the history considered, while the `--` separator clearly separates revisions from the path. This is different from `-L`, which restricts lines.

bash
git blame HEAD~2..HEAD -- src/example.txt
git blame --since=3.weeks -- src/example.txt

When a revision boundary is used, lines unchanged since that boundary can be attributed to the boundary commit. Always interpret the result in the context of the selected revision range.

Follow moved and copied lines

Git automatically follows whole-file renames. `-M` detects lines moved within a file, while `-C` detects lines copied from other files. Repeating `-C` increases the breadth of copy detection according to the documented thresholds.

bash
git blame -M src/example.txt
git blame -C -C -C src/example.txt

Quick check

Why would you add `-C`?

Copy substantial lines into a new file in a disposable repository.git blame -C new-file.txt

Merge commits and first-parent history

By default, blame can traverse merge history to determine line origins. `--first-parent` restricts traversal to the first parent at merge commits. This answers a different investigative question: where a line was introduced along the integration branch rather than anywhere in the merged history.

bash
git blame --first-parent src/example.txt

Quick check

What does `--first-parent` change?

Create a merge commit in a disposable repository.git blame --first-parent file.txt

Ignore mechanical revisions

Formatting-only or other mechanical commits can obscure the meaningful origin of lines. `--ignore-rev <rev>` tells blame to ignore a specified revision when attributing lines. `--ignore-revs-file <file>` supplies a file containing revisions to ignore. Ignoring a revision can leave some lines unblamable when Git cannot attribute them elsewhere; that result is part of the diagnostic, not evidence that the ignored revision never changed them.

bash
git blame --ignore-rev HEAD~1 -- src/example.txt
git blame --ignore-revs-file .git-blame-ignore-revs -- src/example.txt

Quick check

What is the purpose of `--ignore-rev`?

Identify a disposable formatting-only commit.git blame --ignore-rev HEAD~1 -- file.txt

Machine-readable output

`--porcelain` produces a format designed for machine consumption. `--line-porcelain` uses the porcelain format but repeats commit information for each line, which can simplify line-by-line processing at the cost of repeated data. `--incremental` emits results incrementally for machine-oriented consumers.

bash
git blame --porcelain src/example.txt
git blame --line-porcelain src/example.txt
git blame --incremental src/example.txt

Quick check

Why use `--line-porcelain` instead of ordinary porcelain?

Process blame output line by line in a disposable repository.git blame --line-porcelain file.txt

Ignore whitespace and control presentation

`-w` tells blame to ignore whitespace when comparing the parent and child versions to find line origins. Other presentation options include showing the original filename or line number, suppressing author identity, showing email, and changing abbreviation length. These options affect attribution or presentation; they do not rewrite history.

bash
git blame -w src/example.txt
git blame -f -n -e src/example.txt
git blame --abbrev=12 src/example.txt

Reverse attribution and alternate contents

`--reverse START..END` reports the last revision in which a line existed within the specified history, which is useful when asking how long a line survived. `--contents <file>` lets blame compare alternate file contents rather than only the current work-tree contents; when used with a revision, the alternate contents are interpreted relative to that revision.

bash
git blame --reverse HEAD~5..HEAD -- src/example.txt
git blame --contents candidate.txt HEAD -- src/example.txt

Quick check

What investigative question does `--reverse START..END` address?

Create a file that gains and later removes a line across several commits.git blame --reverse HEAD~2..HEAD -- file.txt

A disciplined provenance workflow

Use `git blame` after you have identified the relevant file and region. Start with a narrow line range when possible. Follow moved or copied code with `-M`/`-C` when the default attribution stops at a structural change. If merge history obscures the integration story, compare ordinary blame with `--first-parent`. If a known mechanical revision is noise, test an attribution with `--ignore-rev` and record that you changed the attribution rules. For automation, use porcelain formats rather than parsing the human-oriented default display.

bash
git blame -L 120,155 -M -C -- src/example.txt
git blame --first-parent -L 120,155 -- src/example.txt

Quick check

Which statement is correct?

Choose a changed region and inspect both its blame and its responsible commit.git blame -L start,end -- file.txt

What `git blame` does not own

`git blame` does not replace `git grep` for repository-wide content search, `git bisect` for narrowing regressions, or `git log -S/-G` for finding commits where text appeared in diffs. It also does not recover deleted lines or rewrite history.

Practice what you learned

Use the dedicated Git code-completion exercise for this lesson.

Official source boundary

This lesson uses the official Git `git-blame` documentation and the official Git configuration documentation for blame-related configuration. No third-party documentation is used for command semantics.

Was this page helpful?

Mark this learning resource complete to track your learning progress.