Question

As the title says, I want to find every commit whose diff contains specific string.

At the moment, I use

git log -p 'filename'

Which shows less like interface of every diff, where I search for the string. Then I backtrace to find the actual commit msg.

Simple alternative might be to pipe git log -p into grep, but I can not find the commit id or message that way.

Was it helpful?

Solution 2

Here's a one-liner shell script (split into more than one line for formatting purposes) that extracts the rev-numbers of current-branch-reachable commits affecting path where git show -p contains the given pattern. It's not perfect (it will match commit messages as well as diffs) but it should be easy to tweak however you like, from here.

git rev-list HEAD -- path |
while read rev; do
    if git show -p $rev | grep pattern >/dev/null; then
        echo $rev
    fi
done

Note that you can replace git show with, e.g., git diff $rev^ $rev (note that this only compares against first-parent if it's a merge), or git whatchanged $rev, or whatever you like. The main trick is to start with git rev-list to extract all the candidates (commits affecting the given path; omit the -- path part to get all commits starting from HEAD). See git-rev-list(1) for lots of other things you can do with git rev-list.

OTHER TIPS

git log -p -S'string'

can be used to search for commits that add or remove a string. It doesn't behave exactly the same, because it only matches commits that actually add or remove an instance of the pattern, and not (for instance) commits where it occurs in the diff context. But maybe that's good enough for you.

I know this question's been answered for a while now, but I came across this as well and found a different solution so I thought I'd share. Git-log's -G switch should do what you're aksing, where the -S switch would only output commits where the number of occurences of the matched string changes.

From git-log's man page:

-G Look for differences whose patch text contains added/removed lines that match .

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

+    return !regexec(regexp, two->ptr, 1, &regmatch, 0);
...
-    hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);

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

See the pickaxe entry in gitdiffcore(7) for more information.

git log --all -G'my_search' -i -m -p

mnemonic: git log all GIMP

  • --all: search through all possible paths, not just through HEAD.
  • -G: more general than -S because -S searches only for diffs which show different number of occurrences of my_search. -G searches full diffs and accepts regexes.
  • -i[optional]: make -G ignore case.
  • -m: by default git log does not output diffs for merge commits. -m changes this default behaviour making merge commits output full diffs. This is crucial: if a malformed merge commit changed your line you would not be able to see without -m.
  • -p: also output the full patch for each commit found.

you can even connect this to vim. I find it very useful:

git log --no-color --all -G'regex' -i -m -p | vim -

here I'm using --no-color because vim highlights patches for me.

If you're on linux, pipe it through egrep and search on a regex

git log -p 'filename' | egrep '(yourstring|commit-message)'

Have you considered using a pipe and grep command?

Example:

 git log -p | grep 'filename'

You can use git for this, for example:

git log --grep="filename"

Or on a specific file:

git log --grep="filename" README
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top