Skip to content

Searching Project Content with git grep

Large projects may contain hundreds or thousands of files.

Suppose we are working on a Laravel login feature and want to answer questions such as:

  • Where is AuthService used?
  • Which files contain TODO comments?
  • Where is the login method called?
  • Which PHP files mention password?
  • Which tests use LoginRequest?

Opening every file manually would be slow.

Git provides the following command:

Terminal window
git grep

It searches for matching text patterns inside project files known to Git.

The general form is:

Terminal window
git grep "search pattern"

For example:

Terminal window
git grep "AuthService"

git grep is a read-only command. It searches and displays matching content, but it does not modify:

  • The Working Tree.
  • The Staging Area.
  • Existing commits.
  • Repository history.

The important beginner idea is:

grep searches text and prints lines that match a pattern.

When we use it through Git:

Terminal window
git grep

Git performs the search using its knowledge of the repository.

By default, git grep searches the contents of tracked files in the Working Tree. Tracked files are files Git already knows about.

Search pattern

The text you are looking for, such as AuthService.

Tracked files

The Working Tree versions of files Git already tracks.

Matching lines

Displayed as file path, line, and content.

It does not search untracked files by default, and it does not search every previous commit in repository history by default.

It would be inaccurate to say that git grep searches every file and every commit in the repository — that is not the default behavior.

Suppose our Laravel project contains these files:

app/
├── Http/
│ └── Controllers/
│ └── AuthController.php
├── Services/
│ └── AuthService.php
└── Providers/
└── AppServiceProvider.php
tests/
└── Feature/
└── LoginTest.php

Inside the project, the text AuthService appears in several places. Run:

Terminal window
git grep "AuthService"

An illustrative result may look like:

app/Http/Controllers/AuthController.php:use App\Services\AuthService;
app/Http/Controllers/AuthController.php:public function __construct(private AuthService $authService)
app/Providers/AppServiceProvider.php:AuthService::class,
app/Services/AuthService.php:class AuthService
tests/Feature/LoginTest.php:AuthService::class

One result reads as follows:

app/Services/AuthService.php:class AuthService

It contains:

  1. The path of the file: app/Services/AuthService.php
  2. The matching line: class AuthService

The colon separates the displayed file path from the matching content. The exact paths and output depend on the learner’s own project.

A basic search is normally case-sensitive. These patterns are not necessarily treated as identical:

AuthService
authservice
AUTHSERVICE

For example:

Terminal window
git grep "authservice"

may not find AuthService when their letter case differs.

To ignore letter case, use:

Terminal window
git grep -i "authservice"

The long form is:

Terminal window
git grep --ignore-case "authservice"

An illustrative result may contain:

app/Services/AuthService.php:class AuthService
tests/Feature/LoginTest.php:AuthService::class
  • -i means ignore case.
  • It allows uppercase and lowercase forms to match.
  • It changes how the search is performed. It does not modify the source files.

When we find a result, we often need to know its line number. Use:

Terminal window
git grep -n "AuthService"

The long form is:

Terminal window
git grep --line-number "AuthService"

Illustrative output:

app/Http/Controllers/AuthController.php:8:use App\Services\AuthService;
app/Services/AuthService.php:10:class AuthService
tests/Feature/LoginTest.php:14:AuthService::class

One result reads as follows:

app/Services/AuthService.php:10:class AuthService

The parts are:

File path → app/Services/AuthService.php
Line number → 10
Matching line → class AuthService

-n is one of the most useful options because it tells us exactly where to open the file.

The example’s line numbers will not necessarily match every project — they depend on the actual file content.

Options can be combined. For example:

Terminal window
git grep -ni "authservice"

This means:

  • -n: show line numbers.
  • -i: ignore letter case.

Illustrative output:

app/Http/Controllers/AuthController.php:8:use App\Services\AuthService;
app/Services/AuthService.php:10:class AuthService

This is equivalent to:

Terminal window
git grep -n -i "authservice"

Sometimes a short pattern appears inside longer words. Suppose the project contains:

login
loginUser
LoginController

Running:

Terminal window
git grep "login"

may match text containing login as part of a longer word.

To match login at word boundaries, use:

Terminal window
git grep -w "login"

The long form is:

Terminal window
git grep --word-regexp "login"

-w is useful when we want the word itself rather than every larger word containing the same characters. It does not search for a complete line — it matches at word boundaries.

Sometimes we do not need every matching line — we may only want to know which files contain AuthService. Use:

Terminal window
git grep -l "AuthService"

The long form is:

Terminal window
git grep --files-with-matches "AuthService"

Illustrative output:

app/Http/Controllers/AuthController.php
app/Providers/AppServiceProvider.php
app/Services/AuthService.php
tests/Feature/LoginTest.php
  • The matching lines are hidden.
  • Each matching filename is displayed once.
  • This is useful when we want a quick list of affected or related files.

-l does not display line numbers — it displays filenames only.

We may want to search only inside the application code and ignore the test files. Use:

Terminal window
git grep -n "AuthService" -- app/

Illustrative output:

app/Http/Controllers/AuthController.php:8:use App\Services\AuthService;
app/Services/AuthService.php:10:class AuthService

The command breaks down as:

  • git grep performs the search.
  • -n displays line numbers.
  • "AuthService" is the search pattern.
  • -- ends the list of command options.
  • app/ is the pathspec limiting the search location.

Content before -- describes how to search. Paths after -- describe where to search.

The -- separator is not mandatory in every simple git grep command, but it makes the separation between options and paths explicit and prevents ambiguity.

To search only inside tracked PHP files, use:

Terminal window
git grep -n "AuthService" -- '*.php'
  • "AuthService" is the text pattern.
  • -- separates the search arguments from the pathspec.
  • '*.php' limits the search to matching PHP paths.
  • The quotes prevent the shell from expanding the wildcard before Git receives it.

Illustrative output:

app/Http/Controllers/AuthController.php:8:use App\Services\AuthService;
app/Services/AuthService.php:10:class AuthService
tests/Feature/LoginTest.php:14:AuthService::class

Search inside a directory and file extension together

Section titled “Search inside a directory and file extension together”

To search only PHP files inside app/, use:

Terminal window
git grep -n "AuthService" -- 'app/**/*.php'

This pathspec limits the search to matching PHP files inside app/. If your shell or Git version does not accept this pattern, the simpler directory-limited form works reliably:

Terminal window
git grep -n "AuthService" -- app/

A common practical task is finding unfinished work:

Terminal window
git grep -n "TODO"

Illustrative output:

app/Services/AuthService.php:24:// TODO: add login attempt throttling
app/Http/Controllers/AuthController.php:31:// TODO: move response formatting

git grep does not understand the meaning of TODO — it simply searches for matching text.

Suppose a user reports this message:

Invalid credentials

We can search for the text:

Terminal window
git grep -n "Invalid credentials"

Illustrative output:

app/Services/AuthService.php:36:throw ValidationException::withMessages(['email' => 'Invalid credentials']);

This can help us locate the code responsible for a visible message. Not every message shown to users has to exist as a literal string in the source code — it may come from translations, configuration, a database, or another service.

Suppose we want to locate calls to a method named attempt:

Terminal window
git grep -n "attempt(" -- '*.php'

Illustrative output:

app/Services/AuthService.php:28:if (!Auth::attempt($credentials)) {

This is still a text search. It does not understand PHP method resolution or know whether every result calls the same runtime method.

If no matching text is found, git grep normally prints no matching lines. For example:

Terminal window
git grep "NonExistingService"

may return to the command prompt without displaying results. This can mean:

  • The text is not present in the searched tracked files.
  • The letter case differs.
  • The search was limited to the wrong directory or extension.
  • The relevant file is untracked and therefore not searched by default.
  • The code uses a different name.

An empty result is not proof that the idea does not exist anywhere in the complete project history — it only describes the tracked Working Tree files that were searched.

By default, no. Suppose we create a new file:

app/Services/NewLoginService.php

If Git does not track it yet, the normal command:

Terminal window
git grep "NewLoginService"

does not search it by default.

git grep has additional modes that can widen the search, but they are outside this beginner lesson.

git grep

  • Part of Git.
  • Normally run inside a Git repository.
  • Searches tracked files in the Working Tree by default.
  • Understands Git pathspecs.
  • Can be fast and convenient because Git already knows the tracked files.

Normal grep

  • A general operating-system text-search tool.
  • Not limited to Git repositories.
  • Searches the files and paths the user gives it.
  • Exact availability and behavior depend on the operating system and shell.

It would be inaccurate to claim that git grep is always faster than grep, ripgrep, an IDE search, or every other search tool.

The learner wants to investigate the Laravel login feature.

Terminal window
git grep -n "AuthService"
Terminal window
git grep -n "AuthService" -- tests/

Step 3: Search without caring about letter case

Section titled “Step 3: Search without caring about letter case”
Terminal window
git grep -ni "authservice"
Terminal window
git grep -l "AuthService"
Terminal window
git grep -n "TODO" -- app/

Each command answers a different question:

  • Where is AuthService used?
  • Which tests refer to it?
  • Does a differently capitalized form exist?
  • Which files are related to it?
  • Where are unfinished tasks inside app/?
Goal Command
Search tracked file content git grep "AuthService"
Show line numbers git grep -n "AuthService"
Ignore letter case git grep -i "authservice"
Combine line numbers and ignore case git grep -ni "authservice"
Match at word boundaries git grep -w "login"
Show only filenames git grep -l "AuthService"
Search inside one directory git grep -n "AuthService" -- app/
Search only PHP files git grep -n "AuthService" -- '*.php'
Find TODO comments git grep -n "TODO"

git grep answers: “Which tracked files in my current Working Tree contain this text, and where does it appear?”