spraff spraff - 3 months ago 9
Git Question

How do I search within changes against the last Git checkout/commit?

A change in my working copy of a Git repository caused an error which mentions a variable

foo
and I want to find which files and lines contain a changed line in my working copy which mentions
foo
.

If I do
git diff path/file
it launches a visual editor, so I can't grep in the shell. Even if that worked, it would omit the name of the file in question.

This answer seems closer to what I want, but it is overstuffed with irrelevant examples using terminology I don't really understand.

I don't want to search through any history (i.e. commits), I want to search for
foo
within the changes that I currently made since the last checkout/commit.

"Hey, Git, what did I change which contains
foo
and hasn't been committed yet? File names and line numbers, please."

How do I do this?

(I'd also appreciate being able to ask the same question of a visual diff editor, if you happen to know one on Linux which does this.)

Answer

The following script will do almost what you want:

Usage

GIT_EXTERNAL_DIFF="mygitdiff --grep foo" git diff

This will output those lines in you changes that contain foo (including lines where foo disappeared because of your changes).

Each output line starts with the following prefix:

filename: oldlinenum: newlinenum|

The script can also be used without the --grep option, in which case it simply formats the full diff (i.e. providing full context) as described above.

Note that if you have both staged and unstaged changes, to achieve the desired effect you must run git diff against HEAD:

GIT_EXTERNAL_DIFF="mygitdiff --grep foo" git diff HEAD

mygitdiff

#!/bin/bash

my_diff()
{
    diff --old-line-format="$1"':%6dn:      |-%L'     \
         --new-line-format="$1"':      :%6dn|+%L'     \
         --unchanged-line-format="$1"':%6dn:%6dn| %L' \
         $2 $3
}

if [[ $1 == '--grep' ]]
then
    pattern="$2"
    shift 2
    my_diff "$1" "$2" "$5"|grep --color=never '^[^|]\+|[-+].\+'"$pattern"'.*'
else
    my_diff "$1" "$2" "$5"
fi

exit 0

CREDITS Scott Weldon helped to test this script and found a bug in its initial version. Thank you Scott!

Comments