# How react-doctor --staged Mode Works: Internal Pre-Commit Scanning Architecture

> Discover how react-doctor's --staged mode works by scanning only Git staged files. Learn about its internal architecture for efficient pre-commit diagnostics.

- Repository: [Million Software, Inc./react-doctor](https://github.com/millionco/react-doctor)
- Tags: internals
- Published: 2026-05-12

---

**react-doctor's `--staged` flag executes diagnostics exclusively on Git staged files by creating a temporary snapshot of the index, scanning it in isolation, and remapping diagnostic paths back to the original repository locations.**

The `millionco/react-doctor` repository provides a specialized pre-commit scanning workflow that evaluates only what has been added to Git's staging area, ensuring that linting results match the exact state of the upcoming commit. Unlike standard scans that analyze the working directory, this mode materializes a sandboxed environment to eliminate interference from unstaged modifications. Understanding the internal architecture reveals how the tool orchestrates Git subprocesses, temporary file systems, and path remapping to deliver deterministic results.

## Internal Execution Pipeline

The `--staged` implementation follows a seven-step workflow that bridges Git internals with the scanner's diagnostic engine.

### Step 1: CLI Flag Validation

In [`packages/react-doctor/src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/packages/react-doctor/src/cli.ts) (lines 40-53), the command-line interface first validates that `--staged` is not combined with mutually exclusive flags such as `--diff`. This prevents conflicting scan modes and ensures the subsequent logic operates on a well-defined subset of files.

### Step 2: Discover Staged Source Files

The `getStagedSourceFiles()` function in [`packages/react-doctor/src/utils/get-staged-files.ts`](https://github.com/millionco/react-doctor/blob/main/packages/react-doctor/src/utils/get-staged-files.ts) (lines 36-38) executes `git diff --cached --diff-filter=ACMR` to list paths currently in the index, filtering for source files using the `SOURCE_FILE_PATTERN` regex (`\.(tsx?|jsx?)$`). The `--diff-filter=ACMR` flag specifically excludes deleted files (status D) because they no longer exist in the index and cannot be linted.

### Step 3: Materialize the Temporary Snapshot

For each staged file, the `materializeStagedFiles()` function (lines 52-78 in [`get-staged-files.ts`](https://github.com/millionco/react-doctor/blob/main/get-staged-files.ts)) runs `git show :<path>` to extract the exact blob content from Git's index, bypassing the working tree. These files are written to a fresh temporary directory, which also receives copies of project configuration files like [`tsconfig.json`](https://github.com/millionco/react-doctor/blob/main/tsconfig.json), [`package.json`](https://github.com/millionco/react-doctor/blob/main/package.json), and [`react-doctor.config.json`](https://github.com/millionco/react-doctor/blob/main/react-doctor.config.json) to ensure the scanner can resolve TypeScript and plugin inheritance without accessing the real repository's `.git` directory.

### Step 4: Execute the Scan on the Snapshot

Back in [`cli.ts`](https://github.com/millionco/react-doctor/blob/main/cli.ts) (lines 76-105), the `scan()` function receives `includePaths` limited to the staged file list and a `configOverride` pointing to the temporary directory as the new scan root. This isolates the analysis from any unstaged changes lingering in the working tree.

### Step 5: Remap Diagnostic Paths

After scanning, diagnostic objects contain absolute paths pointing to the temporary directory. The remapping logic in [`cli.ts`](https://github.com/millionco/react-doctor/blob/main/cli.ts) (lines 15-22) rewrites these paths back to the original repository locations by substituting `snapshot.tempDirectory` with `resolvedDirectory`, ensuring that error locations align with the developer's actual file structure.

### Step 6: Emit Remapped Output

The output pipelines—human-readable logs via [`utils/highlighter.ts`](https://github.com/millionco/react-doctor/blob/main/utils/highlighter.ts), JSON reports via [`utils/build-json-report.ts`](https://github.com/millionco/react-doctor/blob/main/utils/build-json-report.ts), and GitHub Actions annotations—receive the remapped diagnostics. JSON reports include the field `mode: "staged"` to indicate the scan context.

### Step 7: Cleanup

Finally, the `cleanup()` callback stored in the snapshot object deletes the temporary directory via a `finally` block in the staged execution logic, guaranteeing no ephemeral files persist on disk regardless of scan success or failure.

## Why react-doctor Uses a Temporary Snapshot

The materialization strategy addresses three critical requirements for reliable pre-commit scanning:

- **Exact Index State**: By reading staged blobs via `git show` rather than working tree files, the scan reflects precisely what will be committed, eliminating false negatives caused by unstaged fixes or false positives from unstaged bugs.
- **Sandboxed Isolation**: Tools like OXLint and ESLint expect a coherent file system layout. Writing staged files to a dedicated temporary directory prevents these tools from resolving relative imports against unstaged or untracked files that would skew the analysis.
- **Configuration Availability**: Copying [`tsconfig.json`](https://github.com/millionco/react-doctor/blob/main/tsconfig.json) and other config files into the snapshot ensures TypeScript resolution and plugin loading function correctly without requiring complex path mapping back to the original repository.

## Error Handling and Edge Cases

The implementation includes specific safeguards for common edge cases:

- **Empty Staged Sets**: If no staged files match the `SOURCE_FILE_PATTERN`, the command returns early with an empty JSON report or the message "No staged source files found."
- **Memory Limits**: All Git subprocesses are constrained by `GIT_SHOW_MAX_BUFFER_BYTES` (10 MiB) defined in [`constants.ts`](https://github.com/millionco/react-doctor/blob/main/constants.ts), preventing out-of-memory errors when processing enormous diff outputs.
- **Deleted Files**: The `--diff-filter=ACMR` flag excludes deleted files from the scan list, as they cannot be materialized from the index.

## Pre-Commit Hook Configuration Examples

### Husky Integration

Configure a pre-commit hook to block commits containing error-level diagnostics:

```bash

# .husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx react-doctor --staged --fail-on error

```

When `--fail-on error` detects an error-level diagnostic, the process exits with code 1, aborting the commit.

### Manual Terminal Usage

Run targeted scans during development:

```bash

# Scan only staged files

react-doctor --staged

# Generate compact JSON for CI pipelines

react-doctor --staged --json --json-compact

```

### Debugging the Snapshot

To inspect the temporary snapshot manually for debugging:

```bash

# Check what files exist in the temp directory

TMP=$(mktemp -d)

# The internal implementation writes to a similar temp path

# Use lsof or process monitoring to identify the active temp directory

# during a react-doctor run

```

> **Note**: The CLI does not expose a `--dry-run` flag; this example illustrates the internal mechanism where staged content is written to a transient location.

## Summary

- **react-doctor --staged mode** creates an isolated temporary snapshot of Git's index to scan exactly what will be committed.
- The workflow spans seven steps: flag validation, staged file discovery, snapshot materialization via `git show`, sandboxed scanning, path remapping, output generation, and cleanup.
- Key implementation files include [`packages/react-doctor/src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/packages/react-doctor/src/cli.ts) for orchestration and [`packages/react-doctor/src/utils/get-staged-files.ts`](https://github.com/millionco/react-doctor/blob/main/packages/react-doctor/src/utils/get-staged-files.ts) for Git interaction.
- The snapshot approach guarantees **deterministic results** by eliminating interference from unstaged working tree changes.
- Safety limits like `GIT_SHOW_MAX_BUFFER_BYTES` and filters like `--diff-filter=ACMR` prevent crashes on large diffs or deleted files.

## Frequently Asked Questions

### Can I combine --staged with --diff in the same command?

No, these flags are mutually exclusive. The CLI validation in [`packages/react-doctor/src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/packages/react-doctor/src/cli.ts) (lines 40-53) explicitly prevents combining `--staged` with `--diff` because they define conflicting file selection strategies—staged files versus differential changes.

### What happens if no staged files match the source pattern?

If `getStagedSourceFiles()` returns an empty list after filtering by `SOURCE_FILE_PATTERN`, the command exits early with an empty JSON array (in JSON mode) or the message "No staged source files found." No temporary directory is created and no scan occurs.

### How does react-doctor handle very large staged files?

The tool sets a hard buffer limit of 10 MiB (`GIT_SHOW_MAX_BUFFER_BYTES` in [`constants.ts`](https://github.com/millionco/react-doctor/blob/main/constants.ts)) when executing `git show` to materialize file contents. If a staged file exceeds this size, the subprocess will truncate or error, preventing out-of-memory crashes during the pre-commit phase.

### Does --staged scan unstaged modifications in tracked files?

No. The `--staged` flag exclusively analyzes content from Git's index using `git show :<path>`, which retrieves the staged blob. Any unstaged modifications in the working tree are ignored, ensuring the scan represents only the changes intended for commit.