본문으로 건너뛰기 Git Interactive Rebase Guide | Squash· Fixup

Git Interactive Rebase Guide | Squash· Fixup

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

CommandWhat it does
pickKeep commit as-is
rewordKeep commit, edit message
editStop here to amend
squashCombine with previous, keep both messages
fixupCombine with previous, discard this message
dropDelete this commit
--autosquashAuto-arrange fixup! commits
--abortCancel rebase, restore original state
--continueAfter resolving conflict, continue
--skipSkip 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.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers Git, Version Control, DevOps, Productivity, Workflow.