Programming
git search grep
Updated Sat, 21 May 2022 14:45:07 GMT

How to grep Git commit diffs or contents for a certain word


In a Git code repository I want to list all commits that contain a certain word. I tried this

git log -p | grep --context=4 "word"

but it does not necessarily give me back the filename (unless it's less that five lines away from the word I searched for. I also tried

git grep "word"

but it gives me only present files and not the history.

How do I search the entire history so I can follow changes on a particular word? I intend to search my codebase for occurrences of word to track down changes (search in files history).




Solution

If you want to find all commits where the commit message contains a given word, use

$ git log --grep=word

If you want to find all commits where "word" was added or removed in the file contents (to be more exact: where the number of occurrences of "word" changed), i.e., search the commit contents, use a so-called 'pickaxe' search with

$ git log -Sword

In modern Git there is also

$ git log -Gword

to look for differences whose added or removed line matches "word" (also commit contents).

A few things to note:

  • -G by default accepts a regex, while -S accepts a string, but it can be modified to accept regexes using the --pickaxe-regex.
  • -S finds commits where the number of occurrences of "word" changed, while -G finds commits where "word" appears in the diff.
  • This means that -S<regex> --pickaxe-regex and -G<regex> do not do exactly the same thing.

The git diff documentation has a nice explanation of the difference:

To illustrate the difference between -S<regex> --pickaxe-regex and -G<regex>, consider a commit with the following diff in the same file:

+    return frotz(nitfol, two->ptr, 1, 0);
...
-    hit = frotz(nitfol, mf2.ptr, 1, 0);

While git log -G"frotz\(nitfol" will show this commit, git log -S"frotz\(nitfol" --pickaxe-regex will not (because the number of occurrences of that string did not change).





Comments (5)

  • +3 – @TankorSmash -S<string> Look for differences that introduce or remove an instance of <string>. -G<string> Look for differences whose added or removed line matches the given <regex>. — Nov 04, 2013 at 20:19  
  • +1 – @m-ric Oh I see, a single string instance, versus an entire line! Thanks — Nov 04, 2013 at 20:35  
  • +3 – @m-ric, @TankorSmash: The difference is that -S<string> is faster because it only checks if number of occurrences of <string> changed, while -G<string> searches added and removed line in every commit diff. — Nov 05, 2013 at 17:18  
  • +3 – If you need to search words with space in between,git log --grep="my words". — May 21, 2014 at 12:45  
  • +4 – @MEM, --grep is different from -S and -G. You can quote the string to each of these arguments. — Aug 12, 2014 at 20:33