Searching Code and History
When you need to know where something is in the code, when it appeared, or why a line looks the way it does, Git has answers: git grep searches files, git log -S finds the commit that added or removed some text, and git blame shows who last changed each line and in which commit.
git grep: search the files
git grep searches tracked files — fast, and it skips ignored folders such as node_modules automatically:
git grep TAX_RATE
basket.js:const TAX_RATE = 0.21; basket.js: return sum * (1 + TAX_RATE);
| Option | Effect |
|---|---|
-n | Show line numbers |
-i | Ignore case |
-w | Match whole words only |
-c | Count matches per file |
-- "*.js" | Search only matching files |
git grep -n "function" -- "*.js"
basket.js:3:function total(items) {
checkout.js:2:function pay(amount) {You can also search the code as it was in any commit — without checking it out:
git grep TAX_RATE HEAD~3
HEAD~3:basket.js:const TAX_RATE = 0.2;
git log -S: when did this text appear?
The "pickaxe" option -S finds commits that changed the number of times a string appears — in other words, commits that added or removed it:
git log --oneline -S "Nothing to pay"
18b710f Reject empty payments
git log --oneline -S "0.2;"
97ceeaa (HEAD -> main) Update tax rate for 2026 afad9da Add basket and checkout
-G takes a regular expression and finds commits whose changed lines match it, which also catches edits that don't add or remove the text outright. Add -p to see the actual changes.
Searching commit messages
git log --oneline --grep="tax" -i
97ceeaa (HEAD -> main) Update tax rate for 2026 d251b62 Include quantity and tax in total
git blame: who changed each line?
git blame annotates every line of a file with the commit, author and date of its last change:
git blame basket.js
97ceeaac (Alex Chen 2026-03-02 09:35:00 +0000 1) const TAX_RATE = 0.21;
^afad9da (Sam Rivera 2026-03-02 09:14:00 +0000 2)
^afad9da (Sam Rivera 2026-03-02 09:14:00 +0000 3) function total(items) {
d251b628 (Alex Chen 2026-03-02 09:21:00 +0000 4) const sum = items.reduce((s, i) => s + i.price * i.qty, 0);
d251b628 (Alex Chen 2026-03-02 09:21:00 +0000 5) return sum * (1 + TAX_RATE);
^afad9da (Sam Rivera 2026-03-02 09:14:00 +0000 6) }A ^ before a hash marks lines that have been unchanged since the first commit in the range. Despite the name, blame is rarely about blame — it's the quickest way to find the commit (and its message) that explains a line. Take the hash from the left and look it up:
git show --no-patch 97ceeaa
commit 97ceeaac8e5a6ce8245b9b5f864ac8126aec73a9 (HEAD -> main)
Author: Alex Chen <alex@example.com>
Date: Mon Mar 2 09:35:00 2026 +0000
Update tax rate for 2026
The rate changed on 1 March; see finance ticket FIN-88.Useful options:
| Option | Effect |
|---|---|
-L 3,6 | Only lines 3 to 6 |
-w | Ignore whitespace-only changes |
-C | Detect lines moved or copied from other files |
--ignore-rev <hash> | Skip a commit, such as a big reformatting |
git blame -L 4,5 basket.js
d251b628 (Alex Chen 2026-03-02 09:21:00 +0000 4) const sum = items.reduce((s, i) => s + i.price * i.qty, 0); d251b628 (Alex Chen 2026-03-02 09:21:00 +0000 5) return sum * (1 + TAX_RATE);
Projects often list mass-reformatting commits in a file called .git-blame-ignore-revs; set blame.ignoreRevsFile to that file (GitHub uses it automatically) so blame looks past them. GitHub and most editors show blame information inline as well.
The history of a few lines
git log -L follows a range of lines through history, showing every change to them:
git log -L 1,1:basket.js --oneline
97ceeaa (HEAD -> main) Update tax rate for 2026 diff --git a/basket.js b/basket.js --- a/basket.js +++ b/basket.js @@ -1,1 +1,1 @@ -const TAX_RATE = 0.2; +const TAX_RATE = 0.21; afad9da Add basket and checkout diff --git a/basket.js b/basket.js --- /dev/null +++ b/basket.js @@ -0,0 +1,1 @@ +const TAX_RATE = 0.2;
Try it yourself
In any project with some history, pick an interesting line. Use git blame to find the commit that last changed it, read that commit with git show, and then use git log -S to find when the line's key word first appeared.