Git Interactive Rebase Guide | Squash· Fixup
이 글의 핵심
Interactive rebase lets you rewrite commit history before merging — squash WIP commits, fix messages, reorder changes, and split large commits. This guide covers every rebase command with real workflow examples.
Why Interactive Rebase?
Before rebase: After rebase:
abc123 WIP abc789 Add user authentication
def456 WIP: actually works ↑ clean, single commit
ghi789 Fix typo ready to merge
jkl012 Add user authentication
Interactive rebase lets you clean up messy development history before it becomes permanent in main.
Common use cases:
- Combine WIP commits into meaningful commits before PR
- Fix a bad commit message from 3 commits ago
- Remove a commit that shouldn’t be in the branch
- Reorder commits for logical clarity
- Split one large commit into focused changes
Basic Syntax
# Rebase last N commits interactively
git rebase -i HEAD~3 # Rebase last 3 commits
# Rebase from a specific commit (exclusive — that commit is not included)
git rebase -i abc1234
# Rebase onto another branch (rebase feature onto main)
git rebase -i main
# Rebase from the point where branch diverged from main
git rebase -i $(git merge-base HEAD main)
The Rebase Editor
When you run git rebase -i HEAD~4, an editor opens:
pick a1b2c3d Add user model
pick e4f5a6b Add auth routes
pick 7c8d9e0 WIP: half-working login
pick 1f2a3b4 Fix login endpoint
# Rebase a1b2c3d..1f2a3b4 onto 9f8e7d6 (4 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, meld into previous commit (keep message)
# f, fixup = like squash, but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# b, break = stop here
# d, drop = remove commit
# l, label = label current HEAD with a name
Commands in Detail
squash / fixup — Combine Commits
# Before
pick a1b2c3d Add user model
pick e4f5a6b Add auth routes
pick 7c8d9e0 WIP: half-working login
pick 1f2a3b4 Fix login endpoint
# After editing — squash/fixup into one commit
pick a1b2c3d Add user model
pick e4f5a6b Add auth routes
pick 7c8d9e0 WIP: half-working login
f 1f2a3b4 Fix login endpoint # fixup: combine, discard message
# squash will open another editor to combine messages
# fixup (f) silently drops the commit message — use for minor fixes
# Squash all WIP commits before pushing
git rebase -i HEAD~5
# Change all "pick" except the first to "squash" or "fixup"
reword — Fix a Commit Message
# Change "pick" to "reword" (or "r")
pick a1b2c3d Add user model
reword e4f5a6b fix thing # ← message needs fixing
pick 7c8d9e0 Add auth routes
# Git will stop at the reword commit and open editor for the message
edit — Stop to Amend a Commit
pick a1b2c3d Add user model
edit e4f5a6b Add auth routes # ← stop here
pick 7c8d9e0 Add login
# During the rebase, git stops at 'edit' commits:
# You can then:
git add forgotten-file.ts
git commit --amend # Add to the commit
git rebase --continue # Resume
drop — Remove a Commit
pick a1b2c3d Add user model
drop e4f5a6b Accidental debug logs # ← delete this commit
pick 7c8d9e0 Add auth routes
# Or just delete the line — same effect
Reorder Commits
# Before (in rebase editor — just move lines)
pick a1b2c3d Add user model
pick e4f5a6b Add auth routes
pick 7c8d9e0 Add tests
# After (reordered — tests before auth routes)
pick a1b2c3d Add user model
pick 7c8d9e0 Add tests # moved up
pick e4f5a6b Add auth routes
# Note: conflicts are possible if commits depend on each other
Common Workflows
Clean Up Before a PR
# You have 6 messy commits on your feature branch
git log --oneline origin/main..HEAD
# 1a2b3c4 fix typo
# 5d6e7f8 WIP 2
# 9g0h1i2 WIP: almost
# 3j4k5l6 add tests
# 7m8n9o0 add auth
# 1p2q3r4 setup
# Clean them up
git rebase -i origin/main
# In the editor:
pick 1p2q3r4 setup
squash 7m8n9o0 add auth # combine with setup? No — fixup/squash adjacent
pick 7m8n9o0 add auth
squash 9g0h1i2 WIP: almost
squash 5d6e7f8 WIP 2
pick 3j4k5l6 add tests
fixup 1a2b3c4 fix typo
# Result: clean 3-commit history
Fix a Commit Message Mid-History
git rebase -i HEAD~5
# Change "pick" to "reword" on the commit with the bad message
# Git stops, opens editor — fix the message
# git rebase --continue
Split One Large Commit
git rebase -i HEAD~3
# Mark the large commit as "edit"
# When git stops:
git reset HEAD~1 # Unstage the commit (keep changes)
git add src/models/ # Stage part 1
git commit -m "Add user model"
git add src/routes/ # Stage part 2
git commit -m "Add auth routes"
git rebase --continue # Continue
git commit —fixup for Automated Squash
# Make a fixup commit for a specific earlier commit
git commit --fixup=abc1234 # Creates: "fixup! <original message>"
# Automatically squash all fixup commits
git rebase -i --autosquash HEAD~5
# fixup commits are automatically placed after their target and marked 'fixup'
Handling Conflicts During Rebase
# When a conflict occurs:
git status # See conflicting files
# Edit files to resolve conflicts
git add resolved-file.ts # Stage resolved files
git rebase --continue # Continue to next commit
# Skip a commit that causes unresolvable conflict (rare)
git rebase --skip
# Abort entirely and return to pre-rebase state
git rebase --abort
Rebase vs Merge
# Workflow: keep feature branch up to date with main
# Option 1: Merge (creates merge commit)
git checkout feature
git merge main
# History: f1 → f2 → merge(f2, m3) → f3
# Option 2: Rebase (linear history)
git checkout feature
git rebase main
# History: m1 → m2 → m3 → f1' → f2' → f3'
# (commits are replayed on top of main)
# Most teams use:
git fetch origin
git rebase origin/main # Update feature branch
# Then: create PR → squash merge or regular merge into main
Safe Rebase Rules
# ✅ Safe: rebase commits that are only on your local branch
git rebase -i HEAD~5 # Local commits only
# ✅ Safe: rebase your feature branch onto main (before others pull it)
git rebase origin/main
# ⚠️ Risky: rebase commits you've pushed to a shared branch
# Anyone who pulled those commits will have diverged history
# If you must:
git push --force-with-lease # Safer than --force (fails if remote was updated)
# ❌ Never: rebase main, develop, or any shared branch
git checkout main
git rebase feature # DO NOT DO THIS
Undo a Rebase
# git reflog shows all recent HEAD positions — even after rebase
git reflog
# HEAD@{0}: rebase finished
# HEAD@{1}: rebase: Add auth routes
# HEAD@{2}: checkout: moving from main to feature
# HEAD@{5}: commit: last good state ← find this
# Reset to pre-rebase state
git reset --hard HEAD@{5}
Quick Reference
| Command | What it does |
|---|---|
pick | Keep commit as-is |
reword | Keep commit, edit message |
edit | Stop here to amend |
squash | Combine with previous, keep both messages |
fixup | Combine with previous, discard this message |
drop | Delete this commit |
--autosquash | Auto-arrange fixup! commits |
--abort | Cancel rebase, restore original state |
--continue | After resolving conflict, continue |
--skip | Skip problematic commit |
Related posts:
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Master git rebase -i for clean commit history. Covers squash, fixup, reword, edit, drop, reorder commits, splitting comm…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
Keywords Covered in This Article (Related Search Terms)
This article covers Git, Version Control, DevOps, Productivity, Workflow.