# Add "git grep" helper

13 messages from 2005-09-12 to 2005-09-13. Participants: Linus Torvalds, Morten Welinder, Junio C Hamano.
Thread: https://gitlist.dev/t/1785

## Linus Torvalds, 2005-09-12 19:06

Subject: Add "git grep" helper
Message-ID: <Pine.LNX.4.58.0509121203210.4098@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121203210.4098%40g5.osdl.org

```

Very convenient shorthand for

	git-ls-files [file-patterns] | xargs grep <pattern>

which I tend to do all the time.

Yes, it's trivial, but it's really nice. I can do

	git grep '\<some_variable\>' arch/i386 include/asm-i386

and it does exactly what you'd think it does. And since it just uses the 
normal git-ls-files file patterns, you can do things like

	git grep something 'include/*.h'

and it will search all header files under the include/ subdirectory.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -76,7 +76,7 @@ SCRIPT_SH = \
 	git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \
 	git-applymbox.sh git-applypatch.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
-	git-merge-resolve.sh
+	git-merge-resolve.sh git-grep.sh
 
 SCRIPT_PERL = \
 	git-archimport.perl git-cvsimport.perl git-relink.perl \
diff --git a/git-grep.sh b/git-grep.sh
new file mode 100755
--- /dev/null
+++ b/git-grep.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+flags=
+while :; do
+  pattern="$1"
+  case "$pattern" in
+  -i|-I|-a|-E|-H|-h|-l)
+    flags="$flags $pattern"
+    shift
+    ;;
+  -*)
+    echo "unknown flag $pattern" >&2
+    exit 1
+    ;;
+  *)
+    break
+    ;;
+  esac
+done
+shift
+git-ls-files -z "$@" | xargs -0 grep $flags "$pattern"

```

## Morten Welinder, 2005-09-12 20:57

Subject: Re: Add "git grep" helper
Message-ID: <118833cc0509121357698005fe@mail.gmail.com>
URL: https://gitlist.dev/e/118833cc0509121357698005fe%40mail.gmail.com
In-Reply-To: <Pine.LNX.4.58.0509121203210.4098@g5.osdl.org>

```
Cute, but what about grep flags like "-w", "-n", and "-c"?

M.

```

## Linus Torvalds, 2005-09-12 21:37

Subject: Re: Add "git grep" helper
Message-ID: <Pine.LNX.4.58.0509121434410.3266@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121434410.3266%40g5.osdl.org
In-Reply-To: <118833cc0509121357698005fe@mail.gmail.com>

```


On Mon, 12 Sep 2005, Morten Welinder wrote:
>
> Cute, but what about grep flags like "-w", "-n", and "-c"?

Hey, add them to the flags list. Or just pass in all flags to grep, I
dunno (I was kind of expecting some flags to go to git-ls-files, but that
may or may not make any sense, and my script obviously didn't end up doing
that).

		Linus

```

## Junio C Hamano, 2005-09-12 21:45

Subject: Re: Add "git grep" helper
Message-ID: <7vbr2y7yfd.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vbr2y7yfd.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121203210.4098@g5.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> Very convenient shorthand for
>
> 	git-ls-files [file-patterns] | xargs grep <pattern>
>
> which I tend to do all the time.

Great minds think alike.  I stopped using 'grep-find' in Emacs
and use "git-ls-fiels -z | xargs -0 grep" instead these days.
Thanks for the patch; applied.

I do not much care about other grep flags but I think you forgot
to special case '-e', so what is in the "master" branch has one
extra commit on top of it for that (it does not seem to have
percolated down yet).

```

## Linus Torvalds, 2005-09-12 22:12

Subject: Re: Add "git grep" helper
Message-ID: <Pine.LNX.4.58.0509121500400.3266@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121500400.3266%40g5.osdl.org
In-Reply-To: <7vbr2y7yfd.fsf@assigned-by-dhcp.cox.net>

```


On Mon, 12 Sep 2005, Junio C Hamano wrote:
> 
> I do not much care about other grep flags but I think you forgot
> to special case '-e', so what is in the "master" branch has one
> extra commit on top of it for that (it does not seem to have
> percolated down yet).

Actually, the more I think about it, the more I think Morten was right, 
and the git-grep case statement should just put all flags in "$flags", and 
any git-ls-files flags can be handled specially before.

We also need special casing for grep flags that take an argument.  So the
end result might be something like the following..

  ...
  case "$pattern" in

    # git-ls-file specific flags
    --others|--exclude=*|--exclude-from=*|--exclude-per-directory=*)
	git_flags="$git_flags $pattern"
	shift
	;;

    # grep flags with an argument
    -B|-C|-m)
	flags="$flags $pattern $2"
	shift
	shift
	;;

    # grep 'pattern' argument
    -e)
	pattern="$2"
	shift
	break
	;;

    # We assume everything else is a regular grep pattern
    -*)
	flags="$flags $pattern"
	shift
	;;
  ...

instead. And it's entirely possible that we'd never want to even bother 
with things like --others and --exclude* at all.

		Linus

```

## Linus Torvalds, 2005-09-12 22:22

Subject: Improve "git grep" flags handling
Message-ID: <Pine.LNX.4.58.0509121519310.3266@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121519310.3266%40g5.osdl.org
In-Reply-To: <Pine.LNX.4.58.0509121500400.3266@g5.osdl.org>

```

This allows any arbitrary flags to "grep", and knows about the few special 
grep flags that take an argument too.

It also allows some flags for git-ls-files, although their usefulness is 
questionable.

With this, something line

	git grep -w -1 pattern

works, without the script enumerating every possible flag.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

On Mon, 12 Sep 2005, Linus Torvalds wrote:
> 
> We also need special casing for grep flags that take an argument.  So the
> end result might be something like the following..

diff --git a/git-grep.sh b/git-grep.sh
--- a/git-grep.sh
+++ b/git-grep.sh
@@ -1,25 +1,38 @@
 #!/bin/sh
 flags=
+git_flags=
 while :; do
   pattern="$1"
   case "$pattern" in
-  -i|-I|-a|-E|-H|-h|-l)
-    flags="$flags $pattern"
-    shift
-    ;;
+  # git-ls-file specific flags
+  --others|--exclude=*|--exclude-from=*|--exclude-per-directory=*)
+      git_flags="$git_flags $pattern"
+      shift
+      ;;
+
+  # grep flags with an argument
+  -B|-C|-m)
+      flags="$flags $pattern $2"
+      shift
+      shift
+      ;;
+
+  # grep 'pattern' argument
   -e)
-    pattern="$2"
-    shift
-    break
-    ;;
+      pattern="$2"
+      shift
+      break
+      ;;
+
+  # We assume everything else is a regular grep pattern
   -*)
-    echo "unknown flag $pattern" >&2
-    exit 1
-    ;;
+      flags="$flags $pattern"
+      shift
+      ;;
   *)
     break
     ;;
   esac
 done
 shift
-git-ls-files -z "$@" | xargs -0 grep $flags -e "$pattern"
+git-ls-files -z $git_flags "$@" | xargs -0 grep $flags -e "$pattern"

```

## Junio C Hamano, 2005-09-12 22:31

Subject: Re: Add "git grep" helper
Message-ID: <7virx57w9t.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7virx57w9t.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121500400.3266@g5.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> Actually, the more I think about it, the more I think Morten was right, 
> and the git-grep case statement should just put all flags in "$flags", and 
> any git-ls-files flags can be handled specially before.
>
> We also need special casing for grep flags that take an argument.  So the
> end result might be something like the following..

Arrrrrrrrrrrrrrrrrrrgh.

Now, whose grep are we going to support?  Should we teach every
flag GNU grep supports that can take a parameter to the script?

Can we cheat and do something like this instead?

    git grep -B 6 -A 2 frotz -- arch/i386
    git grep -B 6 -A 2 frotz --others arch/i386

That is, things up to a known git-ls-files flag  or -- are
passed to grep and the rest is given to git-ls-files.

```

## Junio C Hamano, 2005-09-12 22:37

Subject: Re: Improve "git grep" flags handling
Message-ID: <7vd5nd7w0x.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vd5nd7w0x.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121519310.3266@g5.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> +  # git-ls-file specific flags
> +  --others|--exclude=*|--exclude-from=*|--exclude-per-directory=*)
> +      git_flags="$git_flags $pattern"
> +      shift
> +      ;;

This would not fly well, I am afraid.  --exclude=* are usually
shell globs which would be expanded before you use them
unquoted.

```

## Linus Torvalds, 2005-09-12 22:43

Subject: Re: Improve "git grep" flags handling
Message-ID: <Pine.LNX.4.58.0509121542050.3266@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121542050.3266%40g5.osdl.org
In-Reply-To: <7vd5nd7w0x.fsf@assigned-by-dhcp.cox.net>

```


On Mon, 12 Sep 2005, Junio C Hamano wrote:
> 
> This would not fly well, I am afraid.  --exclude=* are usually
> shell globs which would be expanded before you use them
> unquoted.

Good point. However, since it's unlikely that anybody will use it, maybe 
it's not important - more of a "this is how you could do it if you fixed 
the globbing problem" ;)

It's easy enough to fix if you use bash array variables, but I thought 
adding that was not supposed to be done? Or have people resigned 
themselves to bash extensions ;)

		Linus

```

## Junio C Hamano, 2005-09-12 23:26

Subject: Re: Improve "git grep" flags handling
Message-ID: <7vslw96f6j.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vslw96f6j.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121542050.3266@g5.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> Good point. However, since it's unlikely that anybody will use it, maybe 
> it's not important - more of a "this is how you could do it if you fixed 
> the globbing problem" ;)

Yeah, let's see how tolerant your barf-o-meter is today.  This
would make even *me* barf ;-), but it sometimes may be useful to
be able to say:

    git grep --others --exclude='*.[oa]' '@@GIT_'

------------
#!/bin/sh

# git grep <flags>... <pattern> <path>...

{
    # Pick ls-files arguments only.
    first=yes skip=no pattern_found=no
    for x
    do
	case "$skip" in yes) skip=no; continue ;; esac 
    	case "$x" in
	--cached|--deleted|--others|--killed|--ignored|--exclude=*|\
	--exclude-from=*|\--exclude-per-directory=*)
		test 'yes' = "$first" && set x
		set "$@" "$x"
		first=no
		;;
	-A|-B|-C|-D|-d|-f|-m)
		skip=yes
		;;
	-e)
		skip=yes
		pattern_found=yes
		;;
	-*)
		;;
	*)
		case "$pattern_found" in
		yes)
			test 'yes' = "$first" && set x
			set "$@" "$x"
			;;
		no)
			;; # not for us, but for grep
		esac
		;;
	esac
    done
    case "$first" in
    yes) # we did not get *any* ls-files parameter.
    	set x ;;
    esac
    shift
    git-ls-files -z "$@"
} | {
    first=yes eat=no pattern_found=no
    for x
    do
	case "$eat" in
	yes)
		eat=no;
		set "$@" "$x"
		continue
		;;
	esac 
    	case "$x" in
	--cached|--deleted|--others|--killed|--ignored|--exclude=*|\
	--exclude-from=*|\--exclude-per-directory=*)
		;;
	-A|-B|-C|-D|-d|-f|-m)
		test 'yes' = "$first" && set x
		set "$@" "$x"
		first=no
		eat=yes
		;;
	-e)
		test 'yes' = "$first" && set x
		set "$@" "$x"
		eat=yes
		pattern_found=yes
		;;
	-*)
		test 'yes' = "$first" && set x
		set "$@" "$x"
		first=no
		;;
	*)
		case "$pattern_found" in
		yes)
			;; # not for us, but for ls-files
		no)
			test 'yes' = "$first" && set x
			set "$@" "$x"
			pattern_found=yes
		esac
		;;
	esac
    done
    case "$eat,$pattern_found" in
    yes,* | *,no)
    	echo >&2 "* malformed grep parameters"
	exit 1
    esac
    shift
    xargs -0 grep "$@"
}

```

## Linus Torvalds, 2005-09-12 23:46

Subject: Re: Improve "git grep" flags handling
Message-ID: <Pine.LNX.4.58.0509121635060.3266@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509121635060.3266%40g5.osdl.org
In-Reply-To: <7vslw96f6j.fsf@assigned-by-dhcp.cox.net>

```


On Mon, 12 Sep 2005, Junio C Hamano wrote:
> 
> Yeah, let's see how tolerant your barf-o-meter is today.

I'm not barfing, but that's probably because my brain just shut down and 
is desperately trying to gouge my eyes out with a spoon.

Wouldn't it be _much_ nicer to just do

	pattern=
	flags=()
	git_flags=()
	while : ; do
		case "$1" in
		--cached|--deleted|--others|--killed|\
		--ignored|--exclude=*|\
		--exclude-from=*|\--exclude-per-directory=*)
			git_flags=("${git_flags[@]}" "$1")
			;;
		-e)
			pattern="$2"
			shift
			;;
		-A|-B|-C|-D|-d|-f|-m)
			flags=("${flags[@]}" "$1" "$2")
			shift
			;;
		--)
			shift
			break
			;;
		-*)
			flags=("${flags[@]}" "$1")
			;;
		*)
			if [ -z "$pattern" ]; then
				pattern="$1"
				shift
			fi
			break
			;;
		esac
		shift
	done
	git-ls-files -z "${git_flags[@]}" | 
		xargs -0 grep "${flags[@]}" "$pattern"

which does use bash array variables, but dang, it does so for a reason: 
they really are very very useful, and they make it _so_ much more pleasant 
to do these things..

		Linus

```

## Junio C Hamano, 2005-09-12 23:55

Subject: Re: Improve "git grep" flags handling
Message-ID: <7voe6x6dug.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7voe6x6dug.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121635060.3266@g5.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> On Mon, 12 Sep 2005, Junio C Hamano wrote:
>> 
>> Yeah, let's see how tolerant your barf-o-meter is today.
>
> I'm not barfing, but that's probably because my brain just shut down and 
> is desperately trying to gouge my eyes out with a spoon.
>
> Wouldn't it be _much_ nicer to just do

Yes.

```

## Junio C Hamano, 2005-09-13 00:51

Subject: [PATCH] Improve "git grep" flags handling
Message-ID: <7v64t56b83.fsf_-_@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v64t56b83.fsf_-_%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509121635060.3266@g5.osdl.org>

```
This allows any arbitrary flags to "grep", and knows about the few
special grep flags that take an argument too.

It also allows some flags for git-ls-files, although their usefulness
is questionable.

With this, something line

	git grep -w -1 pattern

works, without the script enumerating every possible flag.

[jc: this was the version after I showed Linus a barf-o-meter test
 version that avoids shell arrays.  The emperor penguin must have
 typed this version blindly, since he said:

    I'm not barfing, but that's probably because my brain just shut
    down and is desperately trying to gouge my eyes out with a spoon.

 I slightly fixed it to catch the remaining arguments meant to be
 given git-ls-files.]

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>

---

    Linus Torvalds <torvalds@osdl.org> writes:

    Wouldn't it be _much_ nicer to just do which does use bash
    array variables, but dang, it does so for a reason: they
    really are very very useful, and they make it _so_ much more
    pleasant to do these things..

 Thanks, Linus.  This is what will go into "master" tonight.

 git-grep.sh |   64 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 41 insertions(+), 23 deletions(-)

6df4eef9b10c8de2b9bc3dc769f3a008a1200df7
diff --git a/git-grep.sh b/git-grep.sh
--- a/git-grep.sh
+++ b/git-grep.sh
@@ -1,25 +1,43 @@
 #!/bin/sh
-flags=
-while :; do
-  pattern="$1"
-  case "$pattern" in
-  -i|-I|-a|-E|-H|-h|-l)
-    flags="$flags $pattern"
-    shift
-    ;;
-  -e)
-    pattern="$2"
-    shift
-    break
-    ;;
-  -*)
-    echo "unknown flag $pattern" >&2
-    exit 1
-    ;;
-  *)
-    break
-    ;;
-  esac
+#
+# Copyright (c) Linus Torvalds, 2005
+#
+
+pattern=
+flags=()
+git_flags=()
+while : ; do
+	case "$1" in
+	--cached|--deleted|--others|--killed|\
+	--ignored|--exclude=*|\
+	--exclude-from=*|\--exclude-per-directory=*)
+		git_flags=("${git_flags[@]}" "$1")
+		;;
+	-e)
+		pattern="$2"
+		shift
+		;;
+	-A|-B|-C|-D|-d|-f|-m)
+		flags=("${flags[@]}" "$1" "$2")
+		shift
+		;;
+	--)
+		# The rest are git-ls-files paths (or flags)
+		shift
+		break
+		;;
+	-*)
+		flags=("${flags[@]}" "$1")
+		;;
+	*)
+		if [ -z "$pattern" ]; then
+			pattern="$1"
+			shift
+		fi
+		break
+		;;
+	esac
+	shift
 done
-shift
-git-ls-files -z "$@" | xargs -0 grep $flags -e "$pattern"
+git-ls-files -z "${git_flags[@]}" "$@" |
+	xargs -0 grep "${flags[@]}" "$pattern"

```
