| Crates.io | jj-hunk |
| lib.rs | jj-hunk |
| version | 0.1.0 |
| created_at | 2026-01-10 11:27:48.205607+00 |
| updated_at | 2026-01-10 11:27:48.205607+00 |
| description | Programmatic hunk selection for jj |
| homepage | |
| repository | |
| max_upload_size | |
| id | 2034073 |
| size | 37,460 |
Programmatic hunk selection for jj (Jujutsu).
Select specific diff hunks when splitting, committing, or squashing—without interactive UI. Designed for AI agents and automation.
cargo install jj-hunk
Add to ~/.jjconfig.toml:
[merge-tools.jj-hunk]
program = "jj-hunk"
edit-args = ["select", "$left", "$right"]
jj-hunk --help
# See what hunks exist in your changes
jj-hunk list
# Split changes: hunks 0,1 of foo.rs → first commit, rest → second
jj-hunk split '{"files": {"src/foo.rs": {"hunks": [0, 1]}}, "default": "reset"}' "first commit"
# Commit specific files, leave rest in working copy
jj-hunk commit '{"files": {"src/fix.rs": {"action": "keep"}}, "default": "reset"}' "bug fix"
# Squash specific changes into parent
jj-hunk squash '{"files": {"src/cleanup.rs": {"action": "keep"}}, "default": "reset"}'
| Command | Description |
|---|---|
jj-hunk list |
List all hunks as JSON |
jj-hunk split <spec> <message> |
Split changes into two commits |
jj-hunk commit <spec> <message> |
Commit selected hunks |
jj-hunk squash <spec> |
Squash selected hunks into parent |
{
"files": {
"path/to/file": {"hunks": [0, 2]},
"path/to/other": {"action": "keep"},
"path/to/another": {"action": "reset"}
},
"default": "reset"
}
{"hunks": [indices]} — select specific hunks by index{"action": "keep"} — keep all changes in file{"action": "reset"} — discard all changes in file"default" — action for unlisted files ("keep" or "reset")$ jj-hunk list
{
"src/lib.rs": [
{"index": 0, "type": "replace", "removed": "old_fn()\n", "added": "new_fn()\n"},
{"index": 1, "type": "insert", "removed": "", "added": "// new comment\n"}
],
"src/main.rs": [
{"index": 0, "type": "delete", "removed": "dead_code()\n", "added": ""}
]
}
jj-hunk integrates with jj's --tool mechanism:
jj-hunk split/commit/squash with a JSON specJJ_HUNK_SELECTION env varjj-hunk select $left $right as the diff tool$right to include only selected hunksFor direct control:
echo '{"files": {"src/foo.rs": {"hunks": [0]}}}' > /tmp/spec.json
JJ_HUNK_SELECTION=/tmp/spec.json jj split -i --tool=jj-hunk -m "message"
The primary use case. AI agents can create clean, logical commits without interactive prompts. Instead of dumping all changes into one commit, an agent can:
jj-hunk listThe JSON spec format is easy for LLMs to construct programmatically.
Reorganize messy development history into reviewer-friendly commits. Squash everything, then split by concern:
jj squash --from 'all:trunk()..@-' --into @
jj edit @
jj-hunk split '{"files": {"src/db/schema.ts": {"action": "keep"}}, "default": "reset"}' "feat: add schema"
jj-hunk split '{"files": {"src/api/routes.ts": {"action": "keep"}}, "default": "reset"}' "feat: add routes"
jj describe -m "feat: add UI"
See .claude/commands/clean-history.md for a complete workflow.
Script commit splitting in pipelines. Enforce commit hygiene rules, auto-split by file patterns, or validate that commits are properly scoped.
Keep experimental code in working copy while committing only the finished parts:
jj-hunk commit '{"files": {"src/fix.rs": {"action": "keep"}}, "default": "reset"}' "fix: handle edge case"
# Experimental changes remain uncommitted
This repo includes a Claude Code command for the clean history workflow:
/clean-history [bookmark-name]
The command guides through squashing, splitting, and creating a PR with narrative-quality commits.
MIT