dub reorder
Interactively reorder or drop commits within the current branch, with cascading restack and undo.
dub reorder opens an interactive picker for the commits on the current
branch and lets you move them up/down or mark them as drop. After the
rebase, descendant branches are restacked onto the new tip and an undo entry
is recorded so the whole operation rolls back in one step.
The picker is intentionally limited to reorder and drop. Editing, squashing, and rewording commits are out of scope:
- Edit a commit's contents →
dub modify --pop - Combine adjacent commits →
dub squash - Reword a message →
dub modify --amend -e
Usage
dub reorderThere are no flags — the command always opens a picker against the current branch.
What it does
-
Validates the working tree is clean and the current branch is tracked.
-
Lists commits between the branch's parent (per the tracked stack) and
HEAD, newest first. -
Opens the picker. You can:
- Move a commit up/down in the order.
- Toggle drop on a commit to skip it during the rebase.
- Finish to apply your changes.
- Cancel to bail without rewriting history.
-
If the picker exits unchanged, the command no-ops — no rebase runs.
-
Otherwise, builds a custom
git rebase --interactivetodo with onlypickanddropactions and runs the rebase with that todo applied. -
On rebase conflict, prompts with the same three-option dialog used by
dub restack:- Continue resolving — leaves files in their conflicted state. The
conflict happened inside the reorder rebase, so no
restack-progress.jsonexists; resolve files, then rungit rebase --continue, thendub restackto rebase descendants. - Cancel and roll back — aborts the rebase and resets the branch to its pre-reorder tip via the undo snapshot.
- Exit — leaves the operation in its current state for manual handling.
If instead the cascading restack of descendants hits a conflict (after the reorder itself completed cleanly), the standard
dub continue/dub abortrecovery applies, because that path did write arestack-progress.json. - Continue resolving — leaves files in their conflicted state. The
conflict happened inside the reorder rebase, so no
-
After a clean rebase, runs the standard restack to rebase descendants.
-
Saves a
reorderundo entry sodub undoreverts both the reordered branch and any descendants the cascading restack rewrote.
Examples
Reorder three commits (A, B, C → C, B, A) on the current branch:
dub reorder
# Picker:
# [pick] ghi9012 C
# [pick] def5678 B
# [pick] abc1234 A
# Move each commit to the desired position, then "Finish".Drop the middle commit:
dub reorder
# Picker:
# [pick] ghi9012 C
# [drop] def5678 B <- toggled
# [pick] abc1234 A
# Finish.Roll back the most recent reorder:
dub undo
# ✔ Undid 'reorder': Restored N branches to pre-reorder stateErrors
| Situation | Behavior |
|---|---|
| Working tree has uncommitted changes | Fail with a hint to commit or stash. |
| Current branch is not tracked | Fail with a hint to run dub track. |
| Current branch is the stack root | Fail — root branches don't carry commits to reorder. |
| Branch has zero commits beyond its parent | Fail — nothing to reorder. |
| Branch has exactly one commit | Fail — use dub modify for single-commit edits. |
| All commits marked as drop in the picker | Picker rejects the choice and loops; the rebase would otherwise empty the branch. |
| Rebase conflict (interactive TTY) | Prompts with the standard dub restack three-option dialog (continue / cancel / exit). |
| Rebase conflict (non-interactive: CI, MCP, piped stdin) | Resolves silently to "continue" — the rebase is paused mid-flight and dub reorder returns status: "conflict". Resolve manually then run git rebase --continue + dub restack (or git rebase --abort + dub undo to bail). |
Related
dub modify— edit, amend, or pop the latest commit.dub restack— rebase descendants after a parent moves.dub move— relocate a branch within its stack (not commits).dub undo/dub redo— multi-level undo and redo of mutating commands (20-entry ring).