22

Is it possible to get git grep to search only new or modified files in the index/cache?

(The use-case for this is to use in a pre-commit hook that looks for "debug" code such as console.log in the prospective commit. But I'm not bothered by console.log in "existing" code. Preferably this would also fail to match instances of console.log that are removed, but I can live with those matching!)

mjs
  • 63,493
  • 27
  • 91
  • 122

5 Answers5

24

It turns out the way to do this is not via git grep, but by a completely different command, that also happens to be able to search: git diff-index. (Another triumph for simplicity and orthogonality...)

What I wanted can be achieved via:

$ git diff-index -U --cached -G <regexp> HEAD
mjs
  • 63,493
  • 27
  • 91
  • 122
  • 8
    Note: the search is restricted to the _changed lines_ in new or modified files. To search the entire contents of modified files, see here: https://stackoverflow.com/questions/15592933/how-to-grep-search-in-modified-files-of-working-directory-which-are-not-yet-been – Roy Tinker Feb 05 '18 at 22:27
  • 1
    With --cached it shows only staged files. Without --cached it shows *both* staged and unstaged files. How do I show *only* unstaged files? – Szczepan Hołyszewski Aug 25 '18 at 10:02
14

I usually just do something like:

git diff | grep TODO

If you have enough changed lines to make that annoying, then I add | grep '^+', or start messing around with -[ABC] options.

Tom
  • 42,844
  • 35
  • 95
  • 101
1

I have a Perl program called dirty that detects new or changed files in a repo, and then I can just say grep string_to_find $(dirty).

#!/usr/bin/perl

use warnings;
use strict;

my @lines = qx/svn status 2>&1/;
exit if @lines == 0;

chomp @lines;
my $first = $lines[0];
if ( $first !~ /svn: warning: .+ not a working copy/ ) {
    @lines = grep { !/^[?]/ } @lines; # Ignore unversioned files
    s/^........// for @lines;
    print "$_\n" for @lines;
    exit;
}

@lines = qx/git status --short --untracked-files=no/;
chomp @lines;
s/^...// for @lines;

print "$_\n" for @lines;

Note that it is smart enough to check for dirty files in a Subversion repo or a Git repo, depending on which it detects.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
  • This didn't completely work for me with `git`. It found the text I searched for in an existing changed file, but not in a newly created file in the repo. – Purplejacket Oct 01 '18 at 21:02
1

You can create a git pre-commit hook (it's just a shell script, marked as executable, in your .git/hooks directory) that scans your commit diff for any newly added lines (the ones with + symbol at the beginning for your "debug" pattern), and do an exit 1 if it found such lines.

This tells git commit to abort the commit before starting your $EDITOR for editing the commit message.

holygeek
  • 15,653
  • 1
  • 40
  • 50
1

Here is small aliases for grep'ing changed lines:

    grep-changed = "!f(){ git diff-index -U -G \"$@\" HEAD; };f "
    grep-staged  = "!f(){ git diff-index -U --cached -G \"$@\" HEAD; };f "
Brun
  • 388
  • 3
  • 11