gah - Git Add Hunks
Non-interactive hunk-based staging for git. Stage specific hunks by index, content anchor, regex, or line range—no interactive prompts required. Split hunks into smaller pieces and stage individual changed lines, the non-interactive equivalent of git add -p's split and edit modes.
The Problem
git add -p is great for selective staging, but it requires interactive stdin. That makes it unusable for:
- AI coding agents (Claude, Copilot, Cursor) that can't interact with prompts
- Scripts and automation that need deterministic staging
- Remote/headless environments where interactive TTY isn't available
Installation
CLI
Claude Code
Install the CLI above, then:
/plugin install ThatXliner/gah
Or manually:
mkdir -p .claude/skills git clone https://github.com/ThatXliner/gah.git .claude/skills/gah
Claude Code will auto-use gah for selective staging instead of git add -p.
Other AI Agents (Codex, Cursor, etc.)
Install the CLI, then add the skill instructions from skills/gah/SKILL.md to your agent's context.
Usage
Preview hunks
# Show hunks with indices gah preview src/main.rs # Preview all modified files gah preview --all # Machine-readable JSON output gah preview src/main.rs --json
Output:
[1:Apparent] @@ -341,7 +341,8 @@ fn render_key_summary(
context line
+ new line
- old line
context line
[2:Caption] @@ -363,7 +364,15 @@ fn render_binding_summary(
...
src/main.rs: 2 hunks
The word after the index is the anchor—a single-token content hash that stays stable even when line numbers shift. Anchors are chosen to be single tokens in common LLM tokenizers for maximum efficiency.
Stage by hunk index
# Stage specific hunks gah add src/main.rs --hunks 1,3,5 # Stage a range gah add src/main.rs --hunks 1-3,7
Stage by anchor (content hash)
Anchors are stable identifiers based on hunk content. Unlike indices, they don't change when other hunks are staged or when line numbers shift. Ideal for AI agents that preview once, then stage later.
# Stage by full or partial anchor gah add src/main.rs --anchor Apparent gah add src/main.rs -a App # prefix match works
Stage by regex
# Stage hunks containing a pattern gah add src/main.rs --grep "TODO" # Exclude hunks matching a pattern gah add src/main.rs --grep "debug" --invert
Stage by line range (partial hunks)
--lines stages only the changed lines within the given working-tree range, trimming each matched hunk down to that range. Additions outside the range are dropped; deletions outside the range are left in place. This lets you stage a single changed line out of a larger block—something git add -p's split mode can't do for adjacent changes.
# Stage only the changes on lines 100-150 (working tree lines) gah add src/main.rs --lines 100-150 # Stage one line out of a multi-line edit gah add src/main.rs --lines 142 # Multiple ranges gah add src/main.rs --lines 100-150,200-250
Split hunks into smaller pieces
By default git groups nearby changes into one hunk. --split re-diffs with zero context so each change becomes its own hunk, then you can preview or stage them independently.
# Preview the finest-grained hunks gah preview src/main.rs --split # Stage one of the split-out changes by anchor gah add src/main.rs --split --anchor Beast
Adjacent changed lines can't be separated by --split (git keeps them in one hunk even at zero context)—use --lines to pick individual lines out of such a block.
Stage by AST symbol (requires tree-sitter feature)
Stage hunks that touch specific functions, classes, or other code symbols using tree-sitter AST analysis.
# Install with tree-sitter support cargo install gah --features tree-sitter # Stage hunks touching a function gah add app.py --symbol subtract # Multiple symbols gah add app.py --symbol subtract --symbol multiply
Supported languages: Python, JavaScript, TypeScript, Rust, Go.
Combine filters
gah add src/main.rs --grep "feature" --lines 300-500Dry run
# See what would be staged without actually staging
gah add src/main.rs --hunks 1,3 --dry-runJSON Output
Add --json for structured output:
gah preview src/main.rs --json
{
"file": "src/main.rs",
"hunks": [
{
"index": 1,
"anchor": "Apparent",
"header": "@@ -341,7 +341,8 @@",
"old_start": 341,
"old_count": 7,
"new_start": 341,
"new_count": 8,
"content": "...",
"function_context": "fn render_key_summary(",
"additions": 1,
"deletions": 0
}
]
}Why not just use...
git add -p — Requires interactive stdin. Can't be used programmatically.
git add -N + git add -p — Still requires interactive input.
git apply — Works, but you need to manually construct the patch. gah handles the patch construction for you.
Editor integrations — Great when available, but not always accessible to scripts or agents.
How it works
- Runs
git diffto get the current changes - Parses the diff into individual hunks
- Filters hunks based on your criteria
- Reconstructs a minimal patch for selected hunks
- Applies via
git apply --cached
License
MIT
