Stop a reformatting commit ruining git blame
Someone ran Prettier over the whole repo and now git blame shows only their name — how do I see the real authors?
If you’re seeing this error
fatal: could not open object name list: .git-blame-ignore-revsYou’re in the right place — the fix is below.
Short answer
Put the hash of the reformatting commit in a file called .git-blame-ignore-revs, then set blame.ignoreRevsFile to it. Blame steps straight past that commit and attributes each line to whoever last changed it meaningfully. GitHub and GitLab both read the same file automatically.
echo "<reformat-commit-hash>" >> .git-blame-ignore-revs
git config blame.ignoreRevsFile .git-blame-ignore-revs
git blame src/app.ts
One file, one setting — and hosted blame views honour it too
Does this match your situation?
- Every line in a file is attributed to one commit titled 'chore: run prettier'.
- A whitespace, tab-to-space or line-ending migration has flattened the history.
- git blame is useless for working out why a line exists.
- 'fatal: could not open object name list: .git-blame-ignore-revs'
Step-by-step fix
Find the commit that flattened everything
Blame the file and look at what dominates it. Once you have the hash of the reformatting commit, everything else follows.
step 1git blame src/app.ts | head -20 git log --oneline --all --grep='format\|prettier\|lint' -i -n 20Create the ignore file
Full 40-character hashes only — abbreviations are rejected. Comments are allowed and worth writing, because in a year nobody will remember what each hash was.
step 2cat > .git-blame-ignore-revs <<'EOF' # Migrate to Prettier across the codebase 2b4a8d1f9c3e5a7b1d0f8e6c4a2b9d7f1e3c5a8b # Convert tabs to spaces 9f3e1c7a5b2d8f4e6a0c9b3d7f1e5a8c2b4d6f0a EOF git add .git-blame-ignore-revs git commit -m "chore: ignore formatting commits in blame"Tell Git to use it
Set it in the repository so it applies to every blame you run there. Committing the file means teammates only need this one command, and many will get it for free from their host's web view.
step 3git config blame.ignoreRevsFile .git-blame-ignore-revs git blame src/app.tsGitHub and GitLab both detect .git-blame-ignore-revs automatically in their blame views — no configuration needed there.
Ignore a commit without any setup
For a one-off investigation you do not need a file at all. --ignore-rev takes a hash directly.
step 4git blame --ignore-rev <hash> src/app.ts git blame --ignore-revs-file .git-blame-ignore-revs src/app.tsIgnore whitespace changes entirely
Independent of the ignore file, -w tells blame to disregard whitespace-only differences. Combining it with -C and -M also follows lines through moves between files, which is where most 'who wrote this?' questions actually end up.
step 5git blame -w src/app.ts git blame -w -C -C -M src/app.ts git log -p --follow -- src/app.ts
Why this works
Blame works by walking history and asking, for each line, which commit last touched it — so a commit that rewrites every line in the repository genuinely is the last one to touch all of them. The information is not lost; it is one layer down, behind a commit that changed presentation rather than meaning. blame.ignoreRevsFile makes that distinction explicit: for the listed commits, blame attributes each line to the commit before instead. The mechanism is deliberately opt-in and stored in the repository rather than inferred, because Git cannot tell a purely cosmetic change from a real one — only the people who made it can, which is why the file is something you curate as your codebase gets reformatted.
If that didn’t work
- 'could not open object name list' means the path is wrong or the file is not committed on this branch.
- Hashes must be the full 40 characters; short ones are silently unusable.
- git log -S'<code>' finds the commit that introduced a string regardless of formatting churn.
- For a file rewritten wholesale, git log --follow -p often reads better than blame.
How to stop it happening again
- Add the hash to .git-blame-ignore-revs in the same pull request that does the reformatting.
- Keep formatting changes in their own commit, never mixed with logic.
- Adopt a formatter early and enforce it in CI so there is one flattening commit rather than many.
- Set blame.ignoreRevsFile in the repository config so nobody has to remember the flag.
Commands used in this guide
git blameShow which commit and author last touched every line of a file.
git logBrowse commit history with as much or as little detail as you want.
git configRead and write Git settings for one repo, your user, or the whole machine.
git diffShow exactly what changed - between your files, the index, commits or branches.
git grepSearch the contents of tracked files - at any point in history.
Still stuck?
Search the full command reference and every other rescue guide — there are 76 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
How do I make git blame skip a formatting commit?
List its full 40-character hash in .git-blame-ignore-revs and run git config blame.ignoreRevsFile .git-blame-ignore-revs. Blame then attributes each line to the last commit that changed it meaningfully rather than to the reformat.
Does GitHub respect .git-blame-ignore-revs?
Yes. GitHub and GitLab both pick the file up automatically in their blame views once it is committed to the default branch, so the fix applies to the web interface as well as the command line.
What is the difference between git blame -w and the ignore-revs file?
-w ignores whitespace-only differences on the fly, which handles indentation churn. The ignore file skips entire named commits, which is what you need when a formatter rewrote quotes, line breaks or import ordering — changes that are not whitespace but still carry no meaning.
Why does Git say it could not open the object name list?
blame.ignoreRevsFile points at a path that does not exist on the current branch, usually because the file has not been committed yet or you are on an older branch. Commit the file, or unset the config with git config --unset blame.ignoreRevsFile.
Can git blame follow a line that moved to another file?
Yes — git blame -C -C -M looks for the line in other files and in earlier commits. It is slower, but it is what finds the real author when code has been extracted into a new module.
Related rescue guides
How do I find which commit introduced a particular piece of code?
git log -S "text" (the pickaxe) finds every commit where the number of occurrences of that string changed — which is how you locate the commit that introduced or deleted it. git log -L traces one function's entire evolution.
Read the fix →Always fixableHow do I find which commit broke my code?
git bisect binary-searches your history. Tell it one commit that works and one that doesn't; it checks out the midpoint and asks you to test, halving the range each time. With git bisect run it tests automatically and names the guilty commit unattended.
Read the fix →Always fixableA file was deleted months ago — how do I find and restore it?
git log --all --full-history -- "**/filename" finds every commit that ever touched the file, including the one that deleted it. Restore it from the commit before the deletion with git checkout <hash>^ -- <path>.
Read the fix →Always fixableHow do I compare two branches in Git?
git diff main..feature compares the two tips; git diff main...feature (three dots) compares against their common ancestor and shows only what the feature branch added. The three-dot form is almost always the one you want for reviewing a branch.
Read the fix →