Interactive rebase
Expert Git CLI
Why this matters
A branch after a real afternoon contains "wip", "fix typo" and "actually fix typo". Interactive rebase turns that into the two or three commits you would have made if you had known where you were going, which makes review easier and history readable.
It also rewrites history, so the rule from lesson 12.3 applies without exception: only on commits nobody else has.
The todo list
$ git rebase -i mainGit opens an editor containing one line per commit, oldest first:
pick 68c4a9d feat: add the difficulty filter
pick a41d0c2 wip
pick 12ae4d1 fix typo
pick 9c8987f docs: document the filter
# Rebase d3b92ec..9c8987f onto d3b92ec (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log messageYou edit the first word of each line, save, and close. Git then replays the commits according to your instructions.
The words
| Word | Does |
|---|---|
| pick | Keep the commit as it is |
| reword | Keep the change, edit the message |
| edit | Stop at this commit so you can amend it or split it |
| squash | Merge into the commit above, and combine the messages |
| fixup | Merge into the commit above, discarding this message |
| drop | Remove the commit entirely |
Two behaviours beyond the words: reordering the lines reorders the commits, and deleting a line is the same as drop, which is why an accidental deletion is worth knowing about.
Squashing, in practice
Change the second and third lines to fixup:
pick 68c4a9d feat: add the difficulty filter
fixup a41d0c2 wip
fixup 12ae4d1 fix typo
pick 9c8987f docs: document the filterSuccessfully rebased and updated refs/heads/feature/21-difficulty-filter.$ git log --oneline -35a1c15c docs: document the filter
a8b40cb feat: add the difficulty filter
d3b92ec chore: add CI configuration and contributing guide
Four commits became two, with the same files. Both remaining commits have new hashes, because their content or their parent changed (lesson 18.1).
Autosquash: the version worth learning
Editing the todo by hand is fine for four commits and tedious for fifteen. Autosquash automates the common case: you notice a mistake in an earlier commit and want the fix folded into it.
$ git commit --fixup 68c4a9dThat makes an ordinary commit whose message is fixup! feat: add the difficulty filter. Then:
$ git rebase -i --autosquash mainGit pre-arranges the todo for you:
pick 68c4a9d feat: add the difficulty filter
fixup 12ae4d1 fixup! feat: add the difficulty filter
pick 9c8987f docs: document the filterSave and close without editing anything, and the fix is absorbed into the commit it belongs to. Set git config --global rebase.autosquash true and --autosquash becomes the default.
This is the workflow to adopt: as you work, --fixup the commit each fix belongs to, then one autosquash rebase before opening the merge request.
Splitting a commit
The one that needs edit:
- Mark the commit
editand save. Git stops there. git reset HEAD~1— the commit is undone, its changes back in your files (lesson 12.4).- Stage and commit the first part, then the second.
git rebase --continue.
Getting out
| Situation | Command |
|---|---|
| A conflict, and you want to finish | Resolve, git add, git rebase --continue |
| A conflict on a commit that no longer matters | git rebase --skip |
| Anything at all going wrong | git rebase --abort |
| It finished and you regret it | git reset --hard ORIG_HEAD, or the reflog (lesson 12.1) |
Nothing here is lost: the original commits are unreferenced but present, and the reflog names them.
Publishing afterwards
Rewriting a pushed branch means the next push is rejected, and the answer is a lease-checked force (lesson 12.8):
$ git push --force-with-leaseYour own feature branch: routine. A branch someone else has checked out: agree it first. A shared branch: no.
How to do it
$ git rebase -i main
$ git commit --fixup <hash>
$ git rebase -i --autosquash main
$ git rebase --continue | --skip | --abortSet your editor first, or the todo opens in something unexpected (lesson 3.3).
There is no built-in interactive rebase. Extensions add one; the integrated terminal is clearer, and the todo opens in VS Code itself if it is your Git editor.
Git → Interactively Rebase from Here… on a commit in the Log gives a dialog with the same operations as buttons, plus reordering by dragging. It is the friendliest interactive rebase of any tool in this course.
Nothing on the platform rebases interactively. What it offers is Squash commits at merge time, which achieves the tidy history without any rewriting on your side (lesson 13.4).
The same: Squash and merge is the platform's version of this for the common case.
Common mistakes
- Rebasing a shared branch. The rule has no exceptions.
- Deleting a line by accident, which drops the commit. Abort and start again.
- Squashing everything into one commit when the branch genuinely did three things.
- Forgetting the branch is pushed, then being surprised by the rejection.
- Editing the todo's comment lines, which do nothing.
- Using
--skipto make a conflict disappear, which drops that commit's change (lesson 12.6).
Try it yourself
Goal: tidy a messy branch two ways.
- On a branch, make four commits: a real one, then "wip", "fix typo", and another real one.
- Run
git rebase -i main, mark the two middle linesfixup, and confirm you end with two commits. - Undo it all with
git reset --hard ORIG_HEADand check the four commits are back. - Now do it with autosquash: make the same mess, but commit the fixes with
git commit --fixup <hash of the commit they belong to>. - Run
git rebase -i --autosquash main, save without editing, and compare the result with step 2.
Expected result: the same tidy history twice, once by editing the todo and once with no editing at all.
Show solution
Step 3 is the reassurance that this is reversible: ORIG_HEAD points at the branch as it was before the rebase, so a rebase you dislike costs one command. Step 5 is the workflow to keep: --fixup as you go, one autosquash before review, and the todo list never needs editing by hand.