Hunk
Hunk gives line-level git staging and non-interactive rebase, built for AI agents rather than a human at a terminal.
Precision staging
Use hunk instead of plain git add when:
- You modified multiple areas of a file but only want to commit some of the changes.
- You want atomic, focused commits carved out of a larger set of changes.
- You need to stage specific line ranges without interactive prompts.
Core workflow:
hunk diff --json # See changes with line numbers (machine-readable)
hunk diff # Human-readable diff with line numbers
hunk stage main.go:42-45 # Stage specific lines
hunk stage main.go:10-20,30-40 # Stage multiple ranges
hunk preview # See what will be committed
hunk commit -m "message" # Commit staged changes
hunk reset # Unstage if needed
FILE:LINES syntax:
file.go:10- Single linefile.go:10-20- Range (inclusive)file.go:10-20,30-40- Multiple ranges in one filefile.go:10 other.go:5-8- Multiple files (space-separated)
Line numbers refer to new file lines (what editors display), not old file lines.
Atomic change groups: when a replacement (deletions + additions with no context between them) is partially selected, hunk automatically includes the entire group. You cannot stage half a replacement, the deletions and additions are atomic. Pure-addition and pure-deletion groups can still be individually line-selected.
Fallback when staging fails: if hunk stage fails with "patch does not apply," fall back to git add <file> for whole-file staging, broader line ranges that cover entire change groups, or stage file-by-file instead of cherry-picking lines across many hunks.
Best practices: run hunk diff --json to get exact line numbers before staging. Use hunk preview to verify the patch looks correct before committing. For focused commits, stage only related changes together.
Programmatic rebase
Use hunk's rebase commands when you need to squash fixup commits into their parent, drop debug/temporary commits before a PR, reorder commits for logical grouping, or run commands (tests) between commits during a rebase.
Core workflow:
hunk rebase list --onto main # See commits to rebase
hunk rebase run --onto main <actions> # Execute rebase
hunk rebase status # Check if rebase in progress
hunk rebase continue # Continue after resolving conflicts
hunk rebase abort # Abort and restore original state
Action syntax (comma-separated):
pick:abc123- Keep commit as-issquash:abc123- Combine with previous (concat messages)fixup:abc123- Combine with previous (discard message)drop:abc123- Remove commit from historyreword:abc123:New message- Change commit messageexec:make test- Run command after previous commit
Common patterns:
# Squash last 2 commits into one
hunk rebase list --onto main --json # Get commit hashes
hunk rebase run --onto main "pick:abc123,squash:def456"
# Drop a debug/temporary commit from history
hunk rebase run --onto main "pick:abc123,drop:debug1,pick:ghi789"
# Run tests after each commit to verify history is clean
hunk rebase run --onto main "pick:abc123,exec:go test ./...,pick:def456,exec:go test ./..."
# Reword a commit message
hunk rebase run --onto main "pick:abc123,reword:def456:fix: correct nil check in handshake"
# Squash multiple fixup commits into their targets
hunk rebase run --onto main "pick:feat1,fixup:typo1,pick:feat2,fixup:typo2"
Auto-squash (preferred for fixup commits):
hunk rebase autosquash --onto main # Squash all fixup!/squash! commits
hunk rebase autosquash --onto main --dry-run # Preview what would be squashed
Create fixups with git commit --fixup=<sha>, then auto-squash.
Conflict handling:
hunk rebase status # Check for conflicts
# Resolve conflicts manually, then:
git add <resolved-files>
hunk rebase continue
# Or abort:
hunk rebase abort
Best practices: always run hunk rebase list --onto <base> --json first to get exact hashes. Prefer autosquash over manual run when squashing fixups. Use fixup (not squash) when you want to silently fold in typo fixes. Run hunk rebase status after a run to verify completion.