How Claude HUD Git Status Features Work: showDirty, showAheadBehind, and showFileStats Explained

The git status features in Claude HUD—showDirty, showAheadBehind, and showFileStats—render real-time repository state by executing three Git commands in src/git.ts and conditionally formatting the output in the renderers based on user configuration flags.

Claude HUD (jarrodwatts/claude-hud) displays repository state directly in your terminal status line through configurable git status features. These optional visual indicators—controlled by showDirty, showAheadBehind, and showFileStats flags—transform raw Git output into compact symbols that appear next to your project path. The implementation spans Git command execution, configuration management, and terminal rendering pipelines.

Git Data Collection Pipeline

All git status features rely on getGitStatus() in src/git.ts, which executes three Git commands with a 1-second timeout to keep the HUD responsive. The function returns a GitStatus object containing branch, isDirty, ahead, behind, and fileStats properties.

Branch Name Detection

The current branch is retrieved using git rev-parse --abbrev-ref HEAD (lines 41–47 in src/git.ts). This provides the base string that appears before any status indicators.

Dirty State and File Statistics

The dirty indicator and file stats both derive from a single porcelain status command:

git --no-optional-locks status --porcelain

In src/git.ts at line 59, the dirty flag is set by checking if any output exists:

isDirty = statusOut.trim().length > 0;

The detailed file statistics are parsed by parseFileStats() (lines 95–117), which walks each porcelain line and categorizes changes:

  • Modified (M, R, C symbols): Counted as modified files
  • Added (A symbol): Staged additions
  • Deleted (D symbol): Removed files
  • Untracked (?? prefix): New untracked files

Ahead/Behind Count Calculation

When showAheadBehind is enabled, Claude HUD queries the upstream relationship using:

git rev-list --left-right --count @{upstream}...HEAD

The output (format: behind ahead) is split and parsed at lines 76–80 in src/git.ts:

const [behindStr, aheadStr] = revOut.trim().split(/\s+/);
behind = parseInt(behindStr, 10) || 0;
ahead  = parseInt(aheadStr, 10) || 0;

Configuration System

User preferences for git status features are defined in src/config.ts. The DEFAULT_CONFIG.gitStatus object (lines 84–88) establishes the following defaults:

gitStatus: {
  enabled: true,
  showDirty: true,
  showAheadBehind: false,
  showFileStats: false,
},

During initialization, loadConfig() (lines 35–48) merges user settings from ~/.claude/config.json with these defaults. The resulting configuration is stored as ctx.config.gitStatus and passed to both rendering engines.

Rendering the Git Status Features

The visual output is constructed in two locations depending on HUD layout: src/render/lines/project.ts (expanded mode, lines 30–62) and src/render/session-line.ts (compact mode, lines 66–100). Both files implement identical logic for the three feature flags.

showDirty: The Dirty Indicator

When showDirty is true (the default) and ctx.gitStatus.isDirty is true, the renderer appends an asterisk to the branch name:

if ((gitConfig?.showDirty ?? true) && ctx.gitStatus.isDirty) {
  gitParts.push('*');
}

This appears in project.ts at lines 36–38 and session-line.ts at lines 73–76, producing output like main* when uncommitted changes exist.

showAheadBehind: Sync Status Arrows

The showAheadBehind feature renders upward and downward arrows indicating divergence from the upstream branch:

if (gitConfig?.showAheadBehind) {
  if (ctx.gitStatus.ahead > 0)  gitParts.push(` ↑${ctx.gitStatus.ahead}`);
  if (ctx.gitStatus.behind > 0) gitParts.push(` ↓${ctx.gitStatus.behind}`);
}

Found in project.ts lines 40–46 and session-line.ts lines 78–85, this generates ↑2 when two commits ahead or ↓1 when one commit behind.

showFileStats: Detailed Change Counters

The showFileStats feature provides granular visibility into working directory changes using Starship-prompt-style symbols:

if (gitConfig?.showFileStats && ctx.gitStatus.fileStats) {
  const { modified, added, deleted, untracked } = ctx.gitStatus.fileStats;
  const statParts: string[] = [];
  if (modified > 0) statParts.push(`!${modified}`);
  if (added > 0)    statParts.push(`+${added}`);
  if (deleted > 0)  statParts.push(`✘${deleted}`);
  if (untracked > 0)statParts.push(`?${untracked}`);
  if (statParts.length) gitParts.push(` ${statParts.join(' ')}`);
}

This logic appears in project.ts lines 49–58 and session-line.ts lines 88–97, producing strings like !3 +2 ✘1 ?4 representing 3 modified, 2 added, 1 deleted, and 4 untracked files.

Final Status Line Assembly

The assembled gitParts array is wrapped with color helpers to produce the final HUD segment:

gitPart = `${magenta('git:(')}${cyan(gitParts.join(''))}${magenta(')')}`;

This creates the familiar git:(main* ↑2 ↓1 !3 +2 ✘1 ?4) format visible in the terminal.

Configuration Examples

To enable all git status features, create or edit ~/.claude/config.json:

{
  "gitStatus": {
    "enabled": true,
    "showDirty": true,
    "showAheadBehind": true,
    "showFileStats": true
  }
}

With this configuration, an expanded layout line renders as:


[Opus]  ▓▓░░░░░░░░ 45% │ project/path git:(main* ↑2 ↓1 !3 +2 ✘1 ?4) ░

Disabling file statistics while retaining dirty and ahead/behind indicators:

{
  "gitStatus": {
    "enabled": true,
    "showDirty": true,
    "showAheadBehind": true,
    "showFileStats": false
  }
}

Produces the simplified output:


git:(main* ↑2 ↓1)

Summary

  • src/git.ts executes three Git commands (rev-parse, status --porcelain, rev-list) to populate the GitStatus object with branch, dirty state, ahead/behind counts, and file statistics.
  • src/config.ts manages the three boolean flags (showDirty, showAheadBehind, showFileStats) through DEFAULT_CONFIG and user configuration merging.
  • src/render/lines/project.ts and src/render/session-line.ts conditionally render symbols based on these flags: * for dirty, ↑N/↓N for sync status, and !M +A ✘D ?U for file stats.
  • All Git commands timeout after 1000ms to prevent HUD freezing on large repositories or network-mounted drives.

Frequently Asked Questions

How does Claude HUD determine if a repository is dirty?

Claude HUD checks the length of git status --porcelain output in src/git.ts at line 59. If the trimmed stdout contains any characters, isDirty becomes true and the renderer appends an asterisk when showDirty is enabled.

What Git command provides the ahead/behind counts for showAheadBehind?

The feature uses git rev-list --left-right --count @{upstream}...HEAD (lines 70–80 in src/git.ts). The command returns two space-separated integers representing commits behind and ahead of the upstream branch, which are parsed and rendered as ↓N and ↑N arrows.

Can I show file statistics without the dirty indicator?

Yes. Set showDirty to false and showFileStats to true in your ~/.claude/config.json. The dirty asterisk will be suppressed while the detailed counters (!M +A ✘D ?U) continue to display specific change counts from the parseFileStats function.

Why does showFileStats default to false?

The showFileStats feature defaults to false in DEFAULT_CONFIG.gitStatus (line 87 of src/config.ts) to maintain a minimal status line by default. Computing file statistics requires parsing every line of porcelain output, and the additional granularity is opt-in for users who want detailed repository state visibility.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →