name: jj:squash description: "Squash changes from working copy into relevant ancestor commits"
Squash Changes Into Ancestors
Move changes from the current working copy into appropriate ancestor commits.
Process
- Run
jj diff --summaryandjj diff --statfor overview - Run
jj log -r ::@- --limit 15to see candidate ancestor commits - Analyze changes:
- Small (≤5 files, ≤200 lines): run
jj diffdirectly - Large: use
/jj-contextfor structured summary
- Small (≤5 files, ≤200 lines): run
- Match changes to commits by path and commit descriptions
- Execute squashes
Basic Usage
Without options, jj squash moves all changes from @ into its parent:
jj squash # squash @ into @-
Whole Files
jj squash --into <change-id> path/to/file.py # -t is short for --into
jj squash --into <change-id> "src/**/*.py" # glob pattern
jj squash --into @-- # into grandparent
Sub-File Chunks
For extracting specific hunks (not whole files):
-
Save original @ change ID:
jj log -r @ --no-graph -T 'change_id' -
Create intermediate commit:
jj new --insert-before @ -
Write only the hunks for target commit (use Edit tool)
-
Squash into target:
jj squash --into <target-change-id> -
Return to rebased @ and remove duplicated hunks:
jj edit <rebased-@-change-id> -
Restore working copy:
jj new
Notes
- Always use change IDs (e.g.,
ksrmwuon) not commit IDs - they're stable across rewrites - After squashing, @ remains as working copy (empty if all changes moved)