Find when a line, function or string was added or removed
How do I find which commit introduced a particular piece of code?
Short answer
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.
git log -S "functionName" --oneline --all
Lists every commit that added or removed that string, across all branches
Does this match your situation?
- You need to know why a strange line exists.
- A config value appeared and nobody knows when.
- You want the commit that deleted a function.
- git blame only shows the last change, not the origin.
Step-by-step fix
Use the pickaxe to find where a string appeared
-S reports commits where the count of that string changed, so you get the commit that added it and the one that removed it — not every commit that happened to touch the same file.
step 1git log -S "AudioManager" --oneline --all # see the actual change in each result: git log -S "AudioManager" -pSearch by pattern instead of exact text
-G takes a regular expression and matches against the diff itself, which is better when the exact spelling varies.
step 2git log -G "api[_-]?key" --oneline --allTrace one function through its whole life
-L follows a line range or a named function and prints every version of it in reverse order. It's the clearest way to understand how something evolved.
step 3git log -L :calculateDamage:src/Combat.cs # or by line range: git log -L 40,60:src/Combat.csBlame for the last change, then walk backwards
Blame shows who touched a line most recently. To find the real origin, blame the parent of that commit and repeat until the line first appears.
step 4git blame -L 42,45 src/Combat.cs # take the commit hash, then look before it: git blame -L 42,45 a1b2c3d^ -- src/Combat.csSearch the content of an old commit directly
git grep works against any commit, so you can ask whether something existed at a given release without checking it out.
step 5git grep "calculateDamage" v1.2.0 git grep -n "TODO" $(git rev-list --all) | head
Why this works
git log normally filters by path, which tells you that a file changed but not what changed inside it. The pickaxe options work on the diff content instead: -S counts occurrences of a string in each commit's before and after states and reports only where that count differs, which isolates introduction and deletion precisely. -L goes further and reconstructs the history of a specific range by following it backwards through renames and edits, which is why it can show a function's entire evolution in one pass.
How to stop it happening again
- Write commit messages explaining why, so this archaeology is rarely needed.
- Keep commits focused - a 200-file commit tells you nothing about intent.
- Add a .git-blame-ignore-revs file so formatting runs don't bury real authorship.
Commands used in this guide
git logBrowse commit history with as much or as little detail as you want.
git blameShow which commit and author last touched every line of a file.
git grepSearch the contents of tracked files - at any point in history.
git showDisplay a single commit, tag or file-at-a-commit in full.
git bisectBinary-search your history to find the exact commit that introduced a bug.
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
How do I find the commit that added a specific line of code?
git log -S "the exact text" --oneline --all lists every commit where the number of occurrences of that string changed, which pinpoints where it was introduced and where it was removed. Add -p to see the diffs.
What is the difference between git log -S and -G?
-S counts occurrences of a fixed string and reports commits where that count changed, so it finds additions and deletions. -G matches a regular expression anywhere in the diff, so it also catches commits that merely modified a line containing the pattern.
How do I see the full history of one function?
git log -L :functionName:path/to/file traces that function through history, printing each version. If Git can't detect the function boundaries for your language, use a line range instead: git log -L 40,60:path/to/file.
Related rescue guides
A 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 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 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 →Always fixableI committed a secret — how do I remove it from Git history?
Rotate the secret first — that's the only step that genuinely protects you. Then purge it from history with git filter-repo (or the BFG Repo-Cleaner) and force-push. Deleting the file in a new commit does nothing, because the old commit still contains it and is still fetchable.
Read the fix →