# How Egonex-AI's Incremental Analysis Detects and Manages Changed Files: A Technical Deep Dive

> Learn how Egonex-AI's incremental analysis leverages Git diffs and a smart staleness check to efficiently manage changed files and update knowledge graphs without full rebuilds.

- Repository: [Egonex/Understand-Anything](https://github.com/Egonex-AI/Understand-Anything)
- Tags: deep-dive
- Published: 2026-06-09

---

**Egonex-AI's incremental analysis uses Git diffs to identify modified files, evaluates staleness via the `isStale` function, and surgically updates the knowledge graph through `mergeGraphUpdate` to avoid expensive full rebuilds.**

The **Egonex-AI/Understand-Anything** repository implements a sophisticated incremental analysis pipeline that keeps code knowledge graphs synchronized with repository changes without recomputing the entire graph on every run. This system leverages Git integration, content fingerprinting, and surgical graph mutations to detect and manage changed files efficiently. Understanding how incremental analysis detects and manages changed files reveals the architecture behind performant, large-scale code comprehension systems.

## Detecting File Changes with Git Integration

The detection mechanism begins with Git-based comparison to identify exactly what has evolved since the last analysis.

### The getChangedFiles Helper

At the core of change detection lies the `getChangedFiles` utility implemented in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts). This function executes a `git diff` command comparing the previously analyzed commit hash stored in the knowledge graph metadata against the current `HEAD`. It returns a plain array of file paths that have been added, removed, or modified in the working directory.

In [`understand-anything-plugin/packages/core/src/staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/staleness.ts) (lines 13-26), the implementation shells out to Git to capture the delta, ensuring the system recognizes every filesystem mutation that could affect the knowledge graph's accuracy. This approach guarantees that no manual file tracking is required—the version control system serves as the single source of truth for incremental analysis.

## Evaluating Staleness Status

Once changed files are identified, the pipeline must determine whether the existing knowledge graph requires rebuilding.

### The isStale Wrapper Function

The `isStale` function (lines 31-42 in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts)) wraps the diff result and provides a clean API for the analysis pipeline. It returns an object containing:

- A boolean `stale` flag indicating whether any changes exist
- The complete list of `changedFiles` requiring attention

The calling code uses this boolean to decide between two execution paths: reusing the persisted knowledge graph when `stale` is false, or triggering an incremental rebuild when true. This early-exit optimization prevents unnecessary computational overhead when repositories remain unchanged between analysis runs.

## Merging Updates into the Knowledge Graph

When staleness is confirmed, the system performs surgical updates rather than regenerating the entire graph structure.

### The mergeGraphUpdate Workflow

The `mergeGraphUpdate` function (lines 54-90 in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts)) implements the critical merge logic that maintains graph integrity while incorporating new analysis data. This function operates through a precise three-step process:

1. **Pruning obsolete nodes** – It removes all nodes and edges belonging to files present in the `changedFiles` list, eliminating stale relationships and definitions
2. **Injecting fresh data** – It merges the newly generated nodes and edges from the current analysis into the existing graph structure
3. **Updating metadata** – It persists the new `gitCommitHash` and `analyzedAt` timestamps to prevent redundant future analyses

Under the hood, the new analysis data originates from the `GraphBuilder` class defined in [`understand-anything-plugin/packages/core/src/analyzer/graph-builder.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/analyzer/graph-builder.ts) (lines 60-138). This builder constructs comprehensive nodes representing files, functions, classes, and imports while recording semantic relationships such as "contains" and "imports" edges that form the knowledge graph's structure.

## Structural Change Detection and Fingerprinting

For scenarios requiring granularity beyond file-level changes, the system implements content fingerprinting to distinguish between superficial and meaningful modifications.

### The Fingerprint Subsystem

The [`fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprint.ts) module provides `buildFingerprintStore` and `compareFingerprints` utilities that compute **structural fingerprints** for each file. Rather than relying solely on Git's text diff, this subsystem:

- Generates content hashes for rapid change detection
- Extracts structural signatures including function signatures, class members, and import/export declarations
- Classifies modifications into three categories:
  - **NONE** – No changes detected
  - **COSMETIC** – Whitespace, comments, or formatting changes that don't affect program semantics
  - **STRUCTURAL** – Modifications to APIs, function signatures, or class hierarchies that impact dependent code

The `compareFingerprints` function (lines 24-46 in [`fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprint.ts)) performs this classification by comparing the current file's fingerprint against the stored baseline. Meanwhile, `buildFingerprintStore` (lines 67-140) maintains the registry of these fingerprints indexed by commit hash. This granular detection allows the merge step to retain nodes for files with purely cosmetic changes while rebuilding only those with structural impact.

## Practical Implementation Examples

The following code demonstrates how to integrate these APIs into custom analysis pipelines.

### Detecting Staleness and Merging Updates

```typescript
import { isStale, mergeGraphUpdate } from "@understand-anything/core";
import { GraphBuilder } from "@understand-anything/core";
import { analyzeProject } from "./my-analyzer"; // your analysis pipeline

const projectDir = "/my/project";
const lastCommit = "a1b2c3d4";               // stored from previous run

// 1️⃣ Find changed files
const { stale, changedFiles } = isStale(projectDir, lastCommit);
if (!stale) {
  console.log("Knowledge graph is up‑to‑date");
  return;
}

// 2️⃣ Run analysis only on the changed files
const { newNodes, newEdges, newCommitHash } = await analyzeProject(projectDir, changedFiles);

// 3️⃣ Load the previous graph (e.g. from .understand-anything/knowledge-graph.json)
const existingGraph = await loadGraph();

// 4️⃣ Merge the updates
const merged = mergeGraphUpdate(
  existingGraph,
  changedFiles,
  newNodes,
  newEdges,
  newCommitHash,
);

// 5️⃣ Persist the merged graph
await saveGraph(merged);

```

### Using the Fingerprint API for Detailed Analysis

```typescript
import { buildFingerprintStore, analyzeChanges } from "@understand-anything/core";
import { PluginRegistry } from "@understand-anything/core";

const registry = new PluginRegistry();               // registers all language extractors
const allFiles = await listProjectFiles(projectDir); // e.g. via glob

// Load previous fingerprint store (if any)
const oldStore = await loadFingerprintStore();

// Re‑build store for the current HEAD
const newStore = buildFingerprintStore(projectDir, allFiles, registry, "HEAD");

// Determine which files actually changed
const changed = getChangedFiles(projectDir, oldStore.gitCommitHash);

// Get a rich analysis
const report = analyzeChanges(projectDir, changed, oldStore, registry);
console.log(report);

```

## Summary

Egonex-AI's incremental analysis architecture delivers efficient code knowledge graph maintenance through several coordinated mechanisms:

- **Git-based detection** via `getChangedFiles` identifies added, removed, and modified files by comparing commit hashes
- **Staleness evaluation** through `isStale` provides a boolean gate that prevents unnecessary rebuilds
- **Surgical graph updates** using `mergeGraphUpdate` prune obsolete nodes and integrate fresh analysis while preserving unchanged data
- **Structural fingerprinting** distinguishes cosmetic from structural changes, optimizing the rebuild scope
- **Metadata tracking** ensures subsequent runs can determine freshness without re-analyzing unchanged repositories

## Frequently Asked Questions

### How does Egonex-AI determine which files have changed?

The system relies on the `getChangedFiles` function in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts) to execute a `git diff` between the last analyzed commit hash stored in the graph metadata and the current `HEAD`. This returns a definitive list of file paths that have been added, removed, or modified since the previous analysis, using Git as the authoritative change tracking mechanism.

### What is the difference between COSMETIC and STRUCTURAL changes?

**COSMETIC** changes include whitespace adjustments, comment modifications, or formatting changes that don't alter program behavior, while **STRUCTURAL** changes affect function signatures, class members, import/export statements, or other semantic elements that impact how code interacts. The fingerprint system in [`fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprint.ts) uses `compareFingerprints` to classify changes accordingly, allowing the pipeline to skip rebuilding nodes for purely cosmetic modifications.

### How does mergeGraphUpdate preserve existing graph data?

The `mergeGraphUpdate` function (lines 54-90 in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts)) first identifies and removes only the nodes and edges associated with files present in the changed files list, then injects the newly analyzed nodes and edges into the existing graph structure. This surgical approach maintains all relationships and metadata for unchanged files while updating only the affected regions, significantly reducing computational overhead compared to full graph regeneration.

### Can the incremental analysis work without Git?

While the primary implementation in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts) depends on Git for change detection via `git diff`, the architecture separates concerns through the `isStale` and `mergeGraphUpdate` interfaces. Custom implementations could theoretically replace the Git-based `getChangedFiles` logic with filesystem watchers or timestamp comparisons, though the official Egonex-AI distribution requires Git to function correctly.