How react-doctor --staged Mode Works: Internal Pre-Commit Scanning Architecture
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 (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 (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) 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, package.json, and 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 (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 (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, JSON reports via 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 showrather 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.jsonand 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 inconstants.ts, preventing out-of-memory errors when processing enormous diff outputs. - Deleted Files: The
--diff-filter=ACMRflag 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:
# .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:
# 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:
# 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-runflag; 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.tsfor orchestration andpackages/react-doctor/src/utils/get-staged-files.tsfor Git interaction. - The snapshot approach guarantees deterministic results by eliminating interference from unstaged working tree changes.
- Safety limits like
GIT_SHOW_MAX_BUFFER_BYTESand filters like--diff-filter=ACMRprevent 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 (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) 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →