Skip to content

Manual Filtering: Globs

Glob patterns provide powerful manual control over which files ripgrep searches. The -g/--glob flag lets you include or exclude files using familiar wildcard syntax, always overriding automatic ignore logic from .gitignore and other sources.

While automatic filtering handles most common cases, glob patterns give you precise control when you need it. They're especially useful for one-off searches where you want to specify exactly which files to search or skip.

Quick Reference

Wildcard Matches Example Description
* Zero or more chars (not /) *.rs All Rust files
? Exactly one char (not /) file?.txt file1.txt, fileA.txt
[...] One char from set [a-z]* Files starting with lowercase
{a,b} Either alternative *.{rs,toml} Rust or TOML files
** Zero or more directories foo/** All files under foo/
! Negation (exclude) !test*.rs Exclude test files

Case-insensitive matching

Use --iglob for single case-insensitive patterns, or --glob-case-insensitive to make all globs case-insensitive.

Basic Glob Syntax

Glob patterns use several standard wildcards:

  • * - Matches zero or more characters (except /)
  • ? - Matches exactly one character (except /)
  • [ab] - Matches one character from the set (a or b)
  • {a,b} - Matches either alternative (a or b)

Wildcard Examples

Match all Rust files:

rg -g '*.rs' 'fn main'

Match files with single character before extension:

rg -g 'file?.txt' pattern

Match files starting with lowercase letters:

rg -g '[a-z]*' pattern

Match either Rust or TOML files:

rg -g '*.{rs,toml}' pattern

Character Classes

Character classes [...] provide flexible character matching:

  • [ab] - Matches a or b
  • [!ab] - Matches any character except a or b
  • [a-z] - Matches any character in the range (lowercase letters)
  • [0-9] - Matches any digit

Examples:

# Match files starting with digits
rg -g '[0-9]*' pattern

# Match files NOT starting with dots (hidden files)
rg -g '[!.]*' pattern

# Match files with alphanumeric names
rg -g '[a-zA-Z0-9]*' pattern

Recursive Matching with **

The ** wildcard matches zero or more directories, enabling recursive searches:

# Match foo in any directory
rg -g '**/foo' pattern

# Match all files under foo/
rg -g 'foo/**' pattern

# Match bar in any subdirectory of foo/
rg -g 'foo/**/bar' pattern

Common Pitfall: Directory Matching

Common Mistake: Directory Matching

A frequent mistake is using -g foo to search directory foo. This glob matches files named exactly foo, not files inside the directory:

# ❌ Wrong: doesn't match foo/bar.rs
rg -g 'foo' pattern

# ✅ Correct: matches all files under foo/
rg -g 'foo/**' pattern

Always use foo/** to match files within a directory.

Including and Excluding Files

By default, glob patterns include files. Prefix a glob with ! to exclude files that match:

# Search all Rust files except tests
rg -g '*.rs' -g '!test*.rs' pattern

# Search src/ but exclude generated code
rg -g 'src/**' -g '!**/generated/**' pattern

Precedence Rules

When multiple globs are specified, later patterns take precedence over earlier ones:

# Include all .rs files, then exclude test files
rg -g '*.rs' -g '!**/tests/**' pattern

# Exclude tests, but re-include integration tests
rg -g '!**/tests/**' -g '**/tests/integration/**' pattern

This allows building complex filters by layering include and exclude patterns.

flowchart TD
    Start[File Encountered] --> Check{"Any -g
patterns?"}
    Check -->|No| Auto["Use Automatic Filtering
.gitignore, .ignore"]
    Check -->|Yes| Eval["Evaluate Glob Patterns
in order"]

    Eval --> Include{"Matches
include
pattern?"}
    Include -->|No| Skip[Skip File]
    Include -->|Yes| Exclude{"Later pattern
excludes?"}

    Exclude -->|Yes !pattern| Skip
    Exclude -->|No| Search[Search File]

    Auto --> AutoCheck{Ignored?}
    AutoCheck -->|Yes| Skip
    AutoCheck -->|No| Search

    style Check fill:#e1f5ff
    style Eval fill:#fff3e0
    style Search fill:#e8f5e9
    style Skip fill:#ffebee

Figure: Glob pattern evaluation flow showing precedence and override behavior.

Multiple Glob Patterns

The -g/--glob flag can be used multiple times. Each pattern applies independently, and a file is searched if any include pattern matches and no exclude pattern matches:

# Search both Rust and Python files
rg -g '*.rs' -g '*.py' pattern  # (1)!

# Search source files but exclude tests and examples
rg -g 'src/**' -g '!**/tests/**' -g '!**/examples/**' pattern  # (2)!
  1. File must match at least one include pattern - searches files ending in .rs OR .py
  2. Include pattern matched first, then exclude patterns filter out matches - searches src/ except tests/ and examples/ subdirectories

Think of multiple -g flags as building up a filter set that refines which files to search.

Brace Expansion

Ripgrep extends standard glob syntax with brace expansion for alternatives:

# Match either Rust or TOML files
rg -g '*.{rs,toml}' pattern  # (1)!

# Match multiple source directories
rg -g '{src,lib,bin}/**/*.rs' pattern  # (2)!

# Match multiple file patterns
rg -g '{Cargo.toml,Cargo.lock,*.rs}' pattern  # (3)!
  1. Expands to two patterns: *.rs and *.toml - matches files with either extension
  2. Expands to three directory patterns: src/**/*.rs, lib/**/*.rs, and bin/**/*.rs
  3. Combines literal filenames with wildcard pattern - matches specific files plus all Rust files
// Source: crates/globset/src/glob.rs:229-231,245
// empty_alternates is set to false by default in GlobOptions
// which means {,c} patterns won't match empty alternatives

Empty Alternatives in Brace Expansion

Empty alternatives like {,c} are supported by the underlying glob library but are disabled by default in ripgrep. The empty_alternates option in the globset crate controls this behavior and is set to false in the default configuration.

This means patterns like test_{,suffix} will only match test_suffix, not test_. This is intentional to avoid unexpected matches with empty strings.

Brace expansion is a ripgrep extension beyond standard .gitignore syntax.

Case-Insensitive Globs

Two flags control case sensitivity for glob matching:

  • --iglob GLOB - Single case-insensitive glob pattern
  • --glob-case-insensitive - Makes all -g patterns case-insensitive
  • --no-glob-case-insensitive - Restores case-sensitive matching (negates --glob-case-insensitive)

Examples:

# Match .html, .HTML, .Html, etc.
rg --iglob '*.html' pattern

# Make all globs case-insensitive
rg --glob-case-insensitive -g '*.rs' -g '*.toml' pattern

# Restore case-sensitive matching after earlier use of --glob-case-insensitive
rg --glob-case-insensitive -g '*.html' --no-glob-case-insensitive -g '*.RS' pattern

Use --iglob when you need one case-insensitive pattern, or --glob-case-insensitive when all your patterns should ignore case. Use --no-glob-case-insensitive to selectively restore case-sensitive matching.

Gitignore Compatibility

Glob patterns use the same syntax as .gitignore files, making them familiar if you already use Git:

  • Patterns match file paths relative to the search root
  • * doesn't match directory separators
  • ** matches zero or more directories
  • ! prefix for negation

This compatibility means you can often copy patterns from .gitignore files directly into -g flags.

Escaping Metacharacters

To match special characters literally, use character class notation:

# Match files with literal asterisk in name
rg -g '*[*]*' pattern

# Match files with literal question mark
rg -g '*[?]*' pattern

Note: Backslash escaping behavior is platform-dependent. Character classes provide reliable cross-platform escaping.

Glob Override Behavior

Important: Glob patterns always override automatic filtering from .gitignore, .ignore, and other sources. When you use -g, you're taking explicit control:

# Search all .rs files, even if .gitignore excludes them
rg -g '*.rs' pattern

# Search ignored directories
rg -g 'target/**/*.rs' pattern

This override behavior gives you ultimate control when automatic filtering is too restrictive.

Ignore Hierarchy and Precedence

Glob patterns with -g/--glob are "override patterns" that sit at the top of ripgrep's ignore hierarchy. The complete precedence order (highest to lowest priority) is:

  1. Override patterns - -g/--glob and --iglob patterns
  2. Custom ignore files - Files specified with --ignore-file
  3. .ignore files - Repository-specific ignore rules
  4. .gitignore files - Git ignore rules
  5. .git/info/exclude - Git local excludes
  6. Global gitignore - User's global Git ignore file
  7. Explicit ignore files - Other repository ignore configurations
  8. Hidden file detection - Automatic filtering of dotfiles
graph TD
    File[File Encountered] --> L1["1. Override Patterns
    -g/--glob, --iglob"]

    L1 -->|Match| Include[Include File]
    L1 -->|No Match| L2["2. Custom Ignore Files
    --ignore-file"]

    L2 -->|Excluded| Exclude[Exclude File]
    L2 -->|No Rule| L3["3. .ignore Files
    Repository-specific"]

    L3 -->|Excluded| Exclude
    L3 -->|No Rule| L4["4. .gitignore Files
    Git ignore rules"]

    L4 -->|Excluded| Exclude
    L4 -->|No Rule| L5["5. .git/info/exclude
    Git local excludes"]

    L5 -->|Excluded| Exclude
    L5 -->|No Rule| L6["6. Global Gitignore
    User's global config"]

    L6 -->|Excluded| Exclude
    L6 -->|No Rule| L7["7. Explicit Ignore Files
    Other repository configs"]

    L7 -->|Excluded| Exclude
    L7 -->|No Rule| L8["8. Hidden File Detection
    Automatic dotfile filtering"]

    L8 -->|Hidden| Exclude
    L8 -->|Visible| Include

    style L1 fill:#e8f5e9
    style Include fill:#c8e6c9
    style Exclude fill:#ffcdd2

Figure: Ignore precedence hierarchy showing how -g/--glob patterns override all automatic filtering.

When you use -g, your patterns take precedence over all automatic ignore sources, which is why globs can force ripgrep to search files that would normally be excluded.

Practical Examples

Common Glob Patterns

Here are practical patterns for common search scenarios:

Search only Rust files:

rg -g '*.rs' 'use std'

Search all files in src/:

rg -g 'src/**' 'TODO'

Exclude test directories:

# Exclude both common test directory naming conventions
rg -g '!**/test/**' -g '!**/tests/**' pattern

Combine multiple patterns:

# Search Rust and TOML in src/, excluding tests
rg -g 'src/**/*.{rs,toml}' -g '!**/tests/**' pattern  # (1)!

  1. Combines directory filtering (src/**), extension matching (.{rs,toml}), and exclusion (!**/tests/**)

Search configuration files:

rg -g '*.{toml,json,yaml,yml}' 'database'

Search only migration files:

rg -g '**/migrations/**/*.sql' 'CREATE TABLE'

Comparison: Globs vs Type Filters

Globs provide more flexibility than type filters (-t), but type filters are more concise for common cases:

Goal Type Filter Glob Pattern
Search Rust files -t rust -g '*.rs'
Search multiple types -t rust -t python -g '*.{rs,py}'
Search specific directory N/A -g 'src/**'
Exclude pattern -T rust -g '!*.rs'
Complex filtering N/A -g 'src/**/*.rs' -g '!**/tests/**'

Use type filters when searching by file type. Use globs when you need path-based filtering or complex include/exclude logic.

Preview Files with --files

Before running a search, preview which files match your globs using --files:

# See which files would be searched
rg --files -g '*.rs' -g '!**/tests/**'

Verify Your Patterns

Always preview with rg --files -g 'pattern' before running complex searches. This helps verify your glob patterns match the files you expect and avoids surprises from incorrect patterns.

Performance Considerations

Glob patterns are evaluated for every file in the search tree. More specific patterns perform better than broad ones:

# ✅ Specific pattern (faster)
rg -g 'src/**/*.rs' pattern        # (1)!

# ❌ Broad pattern requiring more exclusions (slower)
rg -g '**/*.rs' -g '!target/**' -g '!.git/**' -g '!vendor/**' pattern  # (2)!
  1. Targets specific directory, reducing files to evaluate
  2. Matches all .rs files, then excludes large directories - evaluates many unnecessary files

Performance Best Practice

Use include patterns that target specific directories rather than exclude patterns that filter out large portions of the file tree. This reduces the number of files ripgrep needs to evaluate.

Advanced: Glob Optimization

Ripgrep automatically optimizes glob patterns into specialized matching strategies for better performance. The optimizer analyzes each pattern and selects the most efficient matching approach from these strategies:

// Source: crates/globset/src/glob.rs:16-47
enum MatchStrategy {
    Literal(String),           // Exact path match
    BasenameLiteral(String),   // Exact filename match
    Extension(String),         // Extension-only match
    Prefix(String),            // Path prefix match
    Suffix { suffix, component }, // Path suffix match
    RequiredExtension(String), // Extension + regex
    Regex,                     // Full regex evaluation
}

Simple patterns like *.rs are converted to faster Extension matching rather than full regex evaluation. Complex patterns with **, ?, or [...] require Regex matching, which is more expensive.

Performance optimization

Prefer simple extension-based patterns (*.rs) over complex path patterns when possible. The optimizer handles this automatically, but understanding these strategies can help you write more efficient globs.

Summary

Glob patterns give you precise control over which files ripgrep searches:

  • Use -g/--glob for manual file filtering
  • Globs override all automatic ignore logic
  • Support standard wildcards: *, ?, [...], {a,b}
  • Use ** for recursive directory matching
  • Prefix with ! to exclude files
  • Later patterns take precedence over earlier ones
  • Compatible with .gitignore syntax

For most searches, automatic filtering handles file selection. Use globs when you need explicit control over which files to search or skip.