Skip to content
Git Basics: Trace a Line to Its Last Changing Commit

Git Basics: Trace a Line to Its Last Changing Commit

October 28, 2026

When one configuration value looks surprising, inspect the history of that line before reading the entire file history. A two-commit fixture demonstrates a narrow blame query.

Prepare a scratch directory

Tested on Linux with Git 2.52.0 and GNU Bash 5.2.37. You need Bash, a text editor, the named runtime, and standard mktemp, rm, and rmdir utilities. The examples use only controlled local data; generated fixture directories are cleaned automatically.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as demonstrate-blame.sh:

#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
fixture_dir="$(mktemp -d)"
trap 'rm -rf -- "$fixture_dir"' EXIT
export GIT_CONFIG_NOSYSTEM=1
export GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author'
export GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_AUTHOR_DATE='2026-10-28T00:00:00+00:00'
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git init -q -b main "$fixture_dir/repo"
cd -- "$fixture_dir/repo"
git config commit.gpgsign false
git config core.hooksPath /dev/null
printf 'timeout=10\nretries=2\n' > service.conf
git add service.conf
git commit -qm 'Set initial options'
printf 'timeout=30\nretries=2\n' > service.conf
git commit -qam 'Increase timeout'
printf 'Last change to line 1:\n'
git blame --line-porcelain -L 1,1 HEAD -- service.conf | sed -n 's/^summary //p'
printf 'Last change to line 2:\n'
git blame --line-porcelain -L 2,2 HEAD -- service.conf | sed -n 's/^summary //p'
test "$(git blame --line-porcelain -L 1,1 HEAD -- service.conf | sed -n 's/^summary //p')" = 'Increase timeout'
printf 'Current line:\n'
git show HEAD:service.conf | head -1

Run it:

bash demonstrate-blame.sh

Observed output:

Last change to line 1:
Increase timeout
Last change to line 2:
Set initial options
Current line:
timeout=30

Read the result

The line range limits blame to one current line. Porcelain output includes a summary field, which the example extracts without depending on abbreviated hashes or dates. The unchanged second line still points to the initial commit.

Apply it carefully

Blame identifies the last attributed change, not the person responsible for a defect or the reason for a decision. Read that commit and its surrounding discussion. Deleted lines require history searches instead; line numbers refer to the selected revision. Run this script from an ordinary shell with no repository-selection variables such as GIT_DIR or GIT_WORK_TREE set. All commits and cleanup stay inside the newly created temporary fixture.

The official reference describes the behavior and options. These checks cover the fixture above rather than every input or platform.

Clean up

Remove the saved source, return to the starting directory, then remove the empty practice directory:

rm -- demonstrate-blame.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents rather than deleting unknown files.

Acknowledgements

This post was created with assistance from AI.

Last updated on