# Troubleshooting Understand-Anything Incremental Updates: Why Files Aren't Detected

> Fix file detection issues with Understand Anything incremental updates. Learn to resolve stale Git state, incorrect directories, or hidden changes.

- Repository: [Yuxiang Lin/Understand-Anything](https://github.com/Lum1104/Understand-Anything)
- Tags: troubleshooting
- Published: 2026-05-22

---

**When Understand-Anything skips files during an incremental update, the root cause is almost always stale Git state, an incorrect project directory, or untracked changes that `git diff` cannot see.**

Understand-Anything maintains a **knowledge-graph** that reflects the current state of a project. When you run an incremental update (`/understand --incremental`), the system relies on Git to detect modifications since the last analysis. If the tool fails to detect changed files, the knowledge graph will not update, leaving you with stale code intelligence. According to the `Lum1104/Understand-Anything` source code, the detection logic resides in [`packages/core/src/staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/staleness.ts) and depends on a strict contract between the file system, Git history, and the stored project metadata.

## How Incremental Change Detection Works

The incremental pipeline relies on three core functions exported from [`packages/core/src/staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/staleness.ts) to determine what has changed and how to merge new data.

### File Change Detection with `getChangedFiles`

At lines 13–26 of [`staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/staleness.ts), the `getChangedFiles` function executes a shell command to identify modifications:

```typescript
// Conceptual implementation from staleness.ts#L13-L26
const result = execFileSync('git', [
  'diff', 
  `${lastCommitHash}..HEAD`, 
  '--name-only'
], { cwd: projectDir });

```

This function returns an array of file paths that have changed between the stored `lastCommitHash` and the current `HEAD`. If this list is empty, the incremental update will process nothing, even if files appear modified in your editor.

### Staleness Validation via `isStale`

The `isStale` function (lines 31–42) wraps `getChangedFiles` and returns a structured result:

```typescript
interface StaleCheckResult {
  stale: boolean;
  changedFiles: string[];
}

```

If `changedFiles` contains any entries, `stale` is set to `true`, triggering the incremental rebuild. A `false` result short-circuits the pipeline, assuming the existing graph in [`.understand-anything/knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/knowledge-graph.json) is current.

### Graph Merging with `mergeGraphUpdate`

When changes are detected, the system parses only the modified files and calls `mergeGraphUpdate` (lines 45–90). This function performs a surgical update:

1. **Removes** nodes and edges belonging to the changed file paths from the existing graph.
2. **Appends** `newNodes` and `newEdges` generated by the analysis modules ([`graph-builder.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/graph-builder.ts), [`layer-detector.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/layer-detector.ts)).
3. **Updates** the project metadata (`gitCommitHash` and `analyzedAt`) to prevent redundant future processing.

## Why Files Go Undetected: Four Root Causes

If `isStale` returns an empty `changedFiles` array incorrectly, one of the following conditions is occurring according to the source code and test suite in [`staleness.test.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/staleness.test.ts).

### Incorrect `projectDir` Path

The `getChangedFiles` function uses `execFileSync` with the `cwd` option set to `projectDir`. If this path does not point to the **root of the Git repository**, `git diff` executes in the wrong context and returns an empty list. This commonly happens when the tool is invoked from a subdirectory or when a symbolic link obscures the repository root.

### Untracked or Ignored Files

`git diff --name-only` only reports changes to **tracked** files. New files that have not been added to the index (`git add`) or files excluded by `.gitignore` will never appear in the diff output. Consequently, `mergeGraphUpdate` receives no instructions to refresh the graph for these paths, leaving them invisible to the knowledge graph until they are tracked and committed.

### Invalid or Orphaned Commit Hash

Understand-Anything stores the last analyzed commit hash in `graph.project.gitCommitHash`. If this hash becomes invalid—such as after a **force-push** or branch deletion—`git diff` throws an error. The current implementation catches this error silently and falls back to an empty array, causing `isStale` to report `false` even though the graph is materially outdated.

### Shell Execution Failures

Any failure during `execFileSync`—including a missing `git` binary, permission denials, or environment path issues—triggers the error handler in `getChangedFiles`. Rather than crashing the process, the function returns an empty list, masking the underlying system error and appearing as "no files detected."

## Practical Diagnostics and Fixes

Use these TypeScript snippets to manually verify the incremental update mechanism and resolve detection issues.

### Verify Staleness Manually

If the CLI reports no changes, run this diagnostic to see exactly what Git sees:

```typescript
import { isStale } from '@understand-anything/core';
import { join } from 'path';

const projectRoot = '/absolute/path/to/repo-root'; // Must be the git root
const lastHash = 'abc123def456'; // From .understand-anything/knowledge-graph.json

const { stale, changedFiles } = isStale(projectRoot, lastHash);

console.log('Stale:', stale);
console.log('Changed files:', changedFiles);

// Manual verification
if (!stale && changedFiles.length === 0) {
  console.warn('Git reports no diff. Check if files are staged/tracked.');
}

```

*Source:* `isStale` implementation – see lines 34–42 in [[`staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/staleness.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/staleness.ts#L34-L42).

### Force a Graph Merge After Detection

Once you have the correct `changedFiles` list, you can simulate the merge step to verify graph integrity:

```typescript
import { mergeGraphUpdate } from '@understand-anything/core';
import type { KnowledgeGraph, GraphNode, GraphEdge } from '@understand-anything/core';
import { readFile, writeFile } from 'fs/promises';

// Load existing graph
const graphPath = './.understand-anything/knowledge-graph.json';
const existingGraph: KnowledgeGraph = JSON.parse(await readFile(graphPath, 'utf-8'));

// These would come from your parser/analysis phase
const changedPaths = ['src/utils.ts', 'src/helpers.ts'];
const newNodes: GraphNode[] = []; // Populate with parsed AST nodes
const newEdges: GraphEdge[] = []; // Populate with dependency edges
const newCommit = process.env.GIT_COMMIT || 'HEAD';

const updated = mergeGraphUpdate(
  existingGraph,
  changedPaths,
  newNodes,
  newEdges,
  newCommit
);

await writeFile(graphPath, JSON.stringify(updated, null, 2));

```

*Source:* `mergeGraphUpdate` logic – see lines 54–90 in [[`staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/staleness.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/staleness.ts#L54-L90).

### Quick Reference: Symptoms and Solutions

| Symptom | Root Cause | Resolution |
|---------|------------|------------|
| `changedFiles` is always empty | `projectDir` points to a sub-folder | Pass the absolute repository root, not a sub-package or symlink. |
| New files never appear | Files are untracked or in `.gitignore` | Run `git add <file>` to index changes before incremental analysis. |
| `isStale` returns `false` after rebase/force-push | Stored `gitCommitHash` no longer exists | Delete [`.understand-anything/knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/knowledge-graph.json) and run a **full** analysis (`--full`) to reset the baseline hash. |
| Silent failures with no error log | Git binary missing or permission denied | Verify `git` is in the system PATH and the Node.js process has execute permissions. |

## Summary

- **Detection relies on Git:** The `getChangedFiles` function in [`packages/core/src/staleness.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/staleness.ts) uses `git diff <hash>..HEAD --name-only`, meaning untracked files and invalid commit hashes will always yield empty results.
- **Path sensitivity:** The `projectDir` parameter must be the repository root; otherwise, Git executes in the wrong context and reports no changes.
- **Silent failures:** All shell errors in the detection phase are caught and converted to empty arrays, so verify your Git state manually if files are missing.
- **Recovery:** When the stored commit hash becomes invalid (e.g., after force-push), delete the knowledge graph and run a full analysis to re-establish the baseline.

## Frequently Asked Questions

### Why are my new TypeScript files ignored during incremental updates?

Understand-Anything only analyzes **tracked** Git changes. If you create a new file but do not run `git add`, `git diff --name-only` will not report it, and the incremental pipeline will skip it. Stage the file or run a full analysis (`--full`) to include untracked files.

### How do I fix incremental updates after a force-push?

After a force-push, the commit hash stored in [`knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/knowledge-graph.json) may no longer exist in your history, causing `git diff` to fail silently. Delete the [`.understand-anything/knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/knowledge-graph.json) file and run `/understand --full` to generate a fresh graph with the current `HEAD` hash.

### Where does Understand-Anything store the last analyzed commit hash?

The hash is stored inside the [`knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/knowledge-graph.json) file in the `.understand-anything` directory, specifically at the path `project.gitCommitHash`. The `isStale` function reads this value to determine the baseline for `git diff` comparisons.

### What happens if the `projectDir` is incorrect?

If `projectDir` points to a subdirectory or a path outside the Git repository, `getChangedFiles` executes `git diff` in the wrong working directory. Because Git cannot find the repository metadata, it returns an empty file list, and `isStale` incorrectly reports that no files have changed. Always provide the absolute path to the repository root.