# How react-doctor --diff Mode Detects and Scans Changed Files Against a Base Branch

> Discover how react-doctor --diff mode uses Git to scan only changed files against a base branch, optimizing your React code diagnostics.

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

---

**The `--diff` flag uses Git commands to identify files changed between your current branch and a base branch (or uncommitted changes), then restricts the diagnostic scan to only those modified source files.**

**react-doctor** (from the Million ecosystem) provides a targeted scanning mode that avoids analyzing the entire codebase. When activated, the tool executes a precise Git-based detection pipeline to minimize feedback loops during development and CI workflows.

## The Four-Step Detection Pipeline

The diff detection process is implemented across [`src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/src/cli.ts) and [`src/utils/get-diff-files.ts`](https://github.com/millionco/react-doctor/blob/main/src/utils/get-diff-files.ts). It follows a strict resolution order to ensure reliability in various Git states.

### Step 1: Resolve the Effective Diff Flag

The CLI entry point first normalizes user input through `resolveEffectiveDiff()`. This function handles boolean flags, explicit branch names, and the `--full` escape hatch.

If the user passes `--full`, diff mode is immediately disabled regardless of other flags. Otherwise, the function prepares the diff configuration for the next stage.

### Step 2: Gather Diff Information via Git

The core logic resides in `getDiffInfo()` within [`src/utils/get-diff-files.ts`](https://github.com/millionco/react-doctor/blob/main/src/utils/get-diff-files.ts). This utility executes a sequence of Git commands to determine the file delta:

1. **Detect current branch**: Uses `git rev-parse --abbrev-ref HEAD`
2. **Auto-detect default branch**: Reads `origin/HEAD` or falls back to `DEFAULT_BRANCH_CANDIDATES` (defined in [`src/constants.ts`](https://github.com/millionco/react-doctor/blob/main/src/constants.ts) as `["main", "master", "develop", "dev"]`)
3. **Verify explicit base**: If a branch name is provided, validates it with `git rev-parse --verify`
4. **Calculate changes**:
   - If on the base branch itself: captures uncommitted changes via `git diff HEAD`
   - If on a feature branch: finds the merge-base and runs `git diff <merge-base>..HEAD`

The function returns file paths **null-separated** (`-z` flag) for safe handling of special characters, then filters them against `SOURCE_FILE_PATTERN` to exclude non-source files.

### Step 3: Prompt and Mode Resolution

The `resolveDiffMode()` function in [`src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/src/cli.ts) makes the final go/no-go decision:

- Returns `false` if `getDiffInfo` failed or no changes were detected
- When running interactively (TTY), prompts the user: "Only scan changed files?"
- Falls back to a full scan with a warning if the diff set is empty

### Step 4: Restrict the Scan Scope

For each project directory, the CLI builds an `includePaths` array containing only the changed source files (processed through `filterSourceFiles(diffInfo.changedFiles)`). The `scan()` function receives this whitelist, ensuring that linting, dead-code detection, and rule execution operate solely on the modified subset.

## How the Base Branch Is Determined

When `--diff` is passed without an explicit branch name, `detectDefaultBranch()` attempts resolution in this order:

- **Primary**: `origin/HEAD` (resolves to the remote default like `main` or `master`)
- **Fallback**: The first existing ref among `DEFAULT_BRANCH_CANDIDATES` (`main`, `master`, `develop`, `dev`)
- **Failure**: Disables diff mode and runs a full scan

If the user specifies `--diff <branch>`, that string is used directly after verification.

## File Filtering and Pattern Matching

Not all changed files warrant analysis. The system applies `SOURCE_FILE_PATTERN` (defined in [`src/constants.ts`](https://github.com/millionco/react-doctor/blob/main/src/constants.ts)) to the raw Git output to exclude Markdown files, generated assets, and configuration files. Only matching source files enter the `changedFiles` array passed to the scanner.

## Usage Examples

### Scan uncommitted changes on the default branch

```bash
npx -y react-doctor@latest . --verbose --diff

```

On `main`, this scans only unstaged and staged modifications in your working directory.

### Diff against a specific base branch

```bash
npx -y react-doctor@latest . --diff develop

```

The tool verifies that `develop` exists, finds the merge-base between `develop` and `HEAD`, and reports files changed since that divergence point.

### Programmatic integration

```typescript
import { getDiffInfo } from "react-doctor/src/utils/get-diff-files.js";

const diffInfo = getDiffInfo(process.cwd(), "main");
if (diffInfo) {
  console.log("Changed files:", diffInfo.changedFiles);
  // Returns: ['src/components/Button.tsx', 'src/utils/helpers.ts']
}

```

The `changedFiles` array contains repository-relative paths already filtered to source extensions.

## Mode Interactions and Edge Cases

**`--full` override**: Takes precedence over `--diff`, forcing a complete codebase scan regardless of Git state.

**`--staged` exclusivity**: Mutually exclusive with `--diff`. When using `--staged`, the tool utilizes [`src/utils/get-staged-files.ts`](https://github.com/millionco/react-doctor/blob/main/src/utils/get-staged-files.ts) to materialize the Git index into a temporary snapshot and runs a full analysis on that staged content only.

## Summary

- **`resolveEffectiveDiff()`** in [`src/cli.ts`](https://github.com/millionco/react-doctor/blob/main/src/cli.ts) normalizes the `--diff` flag and handles the `--full` override
- **`getDiffInfo()`** in [`src/utils/get-diff-files.ts`](https://github.com/millionco/react-doctor/blob/main/src/utils/get-diff-files.ts) executes Git commands to find the merge-base and list changed files
- **Base branch auto-detection** prefers `origin/HEAD`, falling back to `main`, `master`, `develop`, or `dev`
- **`SOURCE_FILE_PATTERN`** filters Git output to include only relevant source files
- The `scan()` function receives the filtered `changedFiles` array, limiting analysis to the diff set

## Frequently Asked Questions

### What happens if I run `--diff` while on the base branch itself?

The tool detects that the current branch IS the base branch and switches behavior to scan uncommitted changes only (equivalent to `git diff HEAD`). It will not attempt to find a merge-base or compare against the remote.

### Can I use `--diff` with `--staged` simultaneously?

No, these flags are mutually exclusive. `--staged` triggers a separate code path ([`get-staged-files.ts`](https://github.com/millionco/react-doctor/blob/main/get-staged-files.ts)) that analyzes only staged changes through a temporary file snapshot, while `--diff` analyzes the working directory against a base branch.

### How does react-doctor handle file paths with spaces or special characters?

The `getDiffInfo()` function uses Git's `-z` flag for null-terminated path output, ensuring that filenames containing spaces, quotes, or unicode characters are parsed correctly without shell interpolation issues.

### What file extensions are considered "source files"?

The scan respects the `SOURCE_FILE_PATTERN` regular expression defined in [`src/constants.ts`](https://github.com/millionco/react-doctor/blob/main/src/constants.ts). This typically includes JavaScript, TypeScript, JSX, TSX, and other React-relevant extensions, while excluding documentation, images, and build artifacts.