Git Interactive Rebase Squash, Reorder, and Rewrite Commits Before They Hit main
Most devs spam WIP commits and never clean them up. Here's the interactive rebase workflow that turns a messy branch history into a readable PR — covering pick, squash, fixup, reword, drop, and the --autosquash workflow.
If your PR commit history looks like this:
d3a1f2c WIP
8f9c4b1 fix
2a7e3d8 fix2
9c1f5b7 fix for real
4b8d2e9 ugh
7e5c3a1 ok NOW it works
1f9b6d4 cleanup
…then this article is for you.
git rebase -i lets you rewrite your branch’s commit history before anyone else sees it. Squash your WIP commits, fix your messages, drop the debugging commit that prints console.log("AAAA"), and hand reviewers a clean, logical sequence instead of a play-by-play of your afternoon.
What it actually does
git rebase -i HEAD~N replays the last N commits and lets you modify each one before it lands. It opens a TODO list in your editor with every commit listed oldest-first (the opposite of git log — this trips people up every time):
pick d3a1f2c WIP
pick 8f9c4b1 fix
pick 2a7e3d8 fix2
pick 9c1f5b7 fix for real
pick 4b8d2e9 ugh
pick 7e5c3a1 ok NOW it works
pick 1f9b6d4 cleanup
# Rebase b5e7f9a..1f9b6d4 onto b5e7f9a (7 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# d, drop = remove commit
You edit the file, save, and Git executes the list top-to-bottom. The commits are replayed in order, each transformation applied in sequence. If a conflict arises mid-rebase, Git pauses, you fix it, then run git rebase --continue.
The commands that matter
pick
Keep the commit exactly as-is. The default — changing nothing about this one.
squash (s)
Fold this commit into the previous one, then open an editor to combine both commit messages. Use this when you want a say in what the merged message looks like — you get a chance to write a proper combined summary.
fixup (f)
Same as squash, but silently discards this commit’s message. It’s the right command for “WIP”, “fix”, “typo”, and “oops” commits that carry no useful information. No editor prompt — just folds the changes in quietly.
reword (r)
Keep the commit’s changes exactly, but open an editor to fix the message. Useful when the implementation is right but past-you wrote “stuff” as the subject line.
drop (d)
Delete the commit entirely — its changes never land. For debug logging, commented-out experiments, or anything that only existed to help you during development.
edit (e)
Pause the rebase after applying this commit so you can amend it or split it into multiple commits with git reset HEAD~. More advanced, but useful when a single commit did two unrelated things and you want to separate them for bisect or review purposes.
Before and after: a real cleanup
Here’s a realistic branch history after a few hours of development:
$ git log --oneline main..HEAD
1f9b6d4 cleanup
7e5c3a1 ok NOW it works
4b8d2e9 ugh
9c1f5b7 fix for real
2a7e3d8 fix2
8f9c4b1 fix
d3a1f2c WIP: add user auth
6b2e5c8 add login endpoint
a4f1d3b initial auth scaffolding
Führen Sie git rebase -i main and edit the TODO to this:
pick a4f1d3b initial auth scaffolding
squash 6b2e5c8 add login endpoint
reword d3a1f2c WIP: add user auth
fixup 8f9c4b1 fix
fixup 2a7e3d8 fix2
fixup 9c1f5b7 fix for real
fixup 4b8d2e9 ugh
fixup 7e5c3a1 ok NOW it works
drop 1f9b6d4 cleanup
After saving, Git combines the first two commits and prompts for a merged message, lets you reword the “WIP: add user auth” message, silently folds in all five fixup commits, and drops the cleanup commit entirely. The result:
$ git log --oneline main..HEAD
c8f3e2a add user authentication with login endpoint
f5d9b7e initial auth scaffolding
Two clean, logical commits instead of nine breadcrumbs. A reviewer can read those two messages and understand exactly what changed and why.
The –fixup workflow (do this while you work)
If you know a commit needs a follow-up fix, use git commit --fixup <original-hash> while you’re still working. Git writes a commit message of fixup! original message automatically.
# Made a fix to the auth commit
git add -p
git commit --fixup a4f1d3b
# Another fix to the same commit
git add auth.js
git commit --fixup a4f1d3b
When you’re ready to clean up:
git rebase -i --autosquash main
Git reads the fixup! prefixes, moves those commits directly below their targets, and marks them as fixup in the TODO automatically. You open the editor only to confirm the result — no manual rearranging required.
To make --autosquash the default:
git config --global rebase.autoSquash true
This pairs well with git add -p (interactive hunk staging). The workflow: commit logically while you work, tag follow-up fixes with --fixup, run one rebase at the end. Much better than spending twenty minutes wrestling with the TODO editor after the fact.
When not to squash
Squashing everything into one commit isn’t always right. Keep separate commits when:
- The commits represent genuinely distinct concerns. A database migration and a UI update should stay separate. One revert shouldn’t force undoing both.
- Your team uses
git bisect. Fine-grained commits make bisect dramatically more useful. One logical change per commit means bisect can point to exactly where a regression landed. One giant squashed commit makes bisect tell you “somewhere in these 47 files.” - The progression matters for review. Some PRs are easier to review commit-by-commit rather than as one diff. If the commit sequence tells a clearer story than the combined diff, preserve it.
The goal isn’t minimizing commit count. It’s making each commit meaningful. Three focused commits beats one mega-commit and beats nine WIP snapshots.
Force-pushing: when it’s fine and when it isn’t
After rebasing, you’ll need to force-push your branch:
git push --force-with-lease origin your-branch
Verwenden Sie --force-with-leasesein, nicht --force. The difference: --force-with-lease fails if someone else pushed to the branch since your last fetch, preventing you from silently overwriting their work. Plain --force ignores that entirely.
Force-pushing a personal feature branch that nobody else has checked out is fine. Completely normal. Force-pushing main is not — not because force-pushing is inherently evil, but because shared history that others have already pulled creates a divergence problem. The rule isn’t “never force-push” — it’s “never force-push shared history.” Your feature branch, before it’s merged, is yours to rewrite.
If a teammate has checked out your branch (uncommon but it happens), give them a heads-up before you rebase. A git pull --rebase on their end after your push resolves it in most cases, but they need to know it’s coming.
Tools for working with diffs and patches
If you’re regularly working with rebased branches and patches, a few IO Tools make the surrounding workflow easier:
- Git Unified Diff / Patch Generator — generate unified diff output from two text inputs. Useful for producing patches to apply with
git applywhen you’re working across branches or need to share a change without pushing. - 3-Way-Text-Diff-und-Verfassen-Viewer — when a rebase hits conflicts, paste all three versions (base, yours, theirs) and get a visual merge. Faster than parsing
<<<<<<<markers in a terminal. - Git-Log-Formatter & -Aufbereiter — clean up raw
git logoutput into a readable format. Handy when sharing commit history in a PR description or ticket comment.
Clean history is a courtesy, not a formality
Code review is already hard. Don’t make it harder by asking reviewers to mentally reconstruct what your 14-commit branch was trying to do. A clean commit history isn’t about vanity — it’s about making git log, git bisectund git blame actually useful to whoever maintains this code next. That person might be you in six months, staring at a line change with no context and wishing past-you had written a proper commit message instead of “fix.”
Interactive rebase is how you get there. The workflow: commit freely while you work, use --fixup for follow-up changes, run git rebase -i --autosquash main before you open the PR. Fifteen minutes of cleanup that makes the entire history readable forever.
Erweiterungen installieren
IO-Tools zu Ihrem Lieblingsbrowser hinzufügen für sofortigen Zugriff und schnellere Suche
恵 Die Anzeigetafel ist eingetroffen!
Anzeigetafel ist eine unterhaltsame Möglichkeit, Ihre Spiele zu verfolgen. Alle Daten werden in Ihrem Browser gespeichert. Weitere Funktionen folgen in Kürze!
Unverzichtbare Tools
Alle Neuheiten
AlleAktualisieren: Unser neuestes Werkzeug wurde am 20. Juni 2026 hinzugefügt
