Overview
Rebase replays commits on top of a new base. Use it to linearize history before merging, to clean up a feature branch before review, or to move a branch to a different starting point. Rebase rewrites commit SHAs; only use it on commits that have not been pushed to a shared branch. For the broader commit hygiene rules and when to prefer merge over rebase, see git. For the full command reference, see git-commands.
Interactive rebase commands
git rebase -i HEAD~N opens an editor listing the last N commits, one per line. Change the verb to apply an operation.
| Command | Short | What it does |
|---|---|---|
pick | p | Keep the commit as-is. |
reword | r | Keep the commit; open editor to change the message only. |
edit | e | Pause after applying the commit; lets you amend files or split the commit. |
squash | s | Combine with the preceding commit; open editor to merge the commit messages. |
fixup | f | Like squash but discard this commit’s message entirely. |
drop | d | Remove the commit from history. |
exec | x | Run a shell command after the preceding commit; useful for running tests per commit. |
break | b | Pause the rebase for manual intervention; resume with git rebase --continue. |
label | l | Create a label at the current point; used for merging branches in a rebase script. |
merge | (none) | Create a merge commit during an interactive rebase sequence. |
# Example: rebase -i HEAD~4
pick a1b2c3 Add user model
squash d4e5f6 Fix typo in user model
reword 7g8h9i Add auth middleware
fixup 0j1k2l WIP: auth tests
After saving and closing, git applies the commits top-to-bottom, pausing for message edits or conflicts.
Rebase —onto patterns
--onto lets you transplant a range of commits to an arbitrary new base.
| Goal | Command |
|---|---|
| Move branch off old base to new base | git rebase --onto <newbase> <oldbase> <branch> |
| Drop first N commits from a branch | git rebase --onto HEAD~N HEAD~N <branch> |
| Move a sub-branch onto main directly | git rebase --onto main feature-base sub-feature |
| Replay single commit onto another branch | git cherry-pick <sha> (simpler than --onto for one commit) |
# Context: main <- feature-a <- feature-b
# Goal: move feature-b directly onto main, dropping feature-a
git rebase --onto main feature-a feature-b
# Before: main -- A -- B -- C (feature-a)
# \-- D -- E (feature-b)
# After: main -- A -- B -- C (feature-a)
# \-- D' -- E' (feature-b)Conflict resolution
Conflicts arise when replayed commits touch the same lines as the new base.
| Step | Command | Purpose |
|---|---|---|
| 1. See conflicting files | git status | Lists files with conflict markers. |
| 2. Open file and resolve | Edit the file | Remove <<<<<<<, =======, >>>>>>> markers; keep the correct version. |
| 3. Stage the resolution | git add <file> | Mark conflict resolved. |
| 4. Continue the rebase | git rebase --continue | Apply the next commit. |
| 5. Abort if stuck | git rebase --abort | Restore original state; safe escape hatch. |
| 6. Skip a commit | git rebase --skip | Drop the conflicting commit; only use when the commit is genuinely empty after resolution. |
# During conflict
git status
# both modified: src/auth.ts
# Resolve in editor, then:
git add src/auth.ts
git rebase --continueFor complex conflicts, git mergetool opens a three-way diff (yours, theirs, base). Configure with git config merge.tool vimdiff or a GUI tool.
Autosquash workflow
Mark commits as fixups at creation time; collapse them automatically at rebase.
| Command | Purpose |
|---|---|
git commit --fixup=<sha> | Create a fixup! <original message> commit. |
git commit --squash=<sha> | Like --fixup but preserves the message for editing. |
git rebase -i --autosquash main | Automatically reorder and apply fixup/squash commits. |
# Workflow
git commit -m "Add login endpoint" # sha abc123
# later, fix a bug in that commit:
git commit --fixup=abc123
git rebase -i --autosquash main # fixup commit is auto-moved and appliedConfigure rebase.autoSquash = true globally to make --autosquash the default for all interactive rebases.
Safety flags
| Flag | Effect |
|---|---|
--no-ff | Prevent fast-forward; always create a merge commit (used with merge, not rebase). |
--force-with-lease | Push a rebased branch safely; aborts if the remote has new commits since your last fetch. |
--update-refs | Auto-update branch pointers for any branches pointing at rebased commits; useful in a stack. |
--rebase-merges | Preserve merge commits during interactive rebase. |
# Push a rebased branch without clobbering someone else's push
git push --force-with-lease origin feature/authCommon gotchas
- Rebasing shared branches forces every collaborator to recover with
git reset --hard. Only rebase commits that exist on your local branch or a branch only you use. - Interactive rebase of a range that includes merge commits will lose the merge structure unless you pass
--rebase-merges. By default it linearizes everything. git rebase --abortfully restores the pre-rebase state including the branch pointer; it is always safe to run if you are stuck.git rebase --skipdrops the commit, not just the conflict. Use it only when the commit’s changes were already applied by the base (e.g., a cherry-pick that was also merged).- Stash or commit all changes before starting a rebase. A dirty working tree will abort the rebase immediately.
- After a forced push to a remote feature branch, teammates who have checked it out must run
git reset --hard origin/<branch>orgit pull --rebase.