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.

CommandShortWhat it does
pickpKeep the commit as-is.
rewordrKeep the commit; open editor to change the message only.
editePause after applying the commit; lets you amend files or split the commit.
squashsCombine with the preceding commit; open editor to merge the commit messages.
fixupfLike squash but discard this commit’s message entirely.
dropdRemove the commit from history.
execxRun a shell command after the preceding commit; useful for running tests per commit.
breakbPause the rebase for manual intervention; resume with git rebase --continue.
labellCreate 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.

GoalCommand
Move branch off old base to new basegit rebase --onto <newbase> <oldbase> <branch>
Drop first N commits from a branchgit rebase --onto HEAD~N HEAD~N <branch>
Move a sub-branch onto main directlygit rebase --onto main feature-base sub-feature
Replay single commit onto another branchgit 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.

StepCommandPurpose
1. See conflicting filesgit statusLists files with conflict markers.
2. Open file and resolveEdit the fileRemove <<<<<<<, =======, >>>>>>> markers; keep the correct version.
3. Stage the resolutiongit add <file>Mark conflict resolved.
4. Continue the rebasegit rebase --continueApply the next commit.
5. Abort if stuckgit rebase --abortRestore original state; safe escape hatch.
6. Skip a commitgit rebase --skipDrop 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 --continue

For 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.

CommandPurpose
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 mainAutomatically 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 applied

Configure rebase.autoSquash = true globally to make --autosquash the default for all interactive rebases.

Safety flags

FlagEffect
--no-ffPrevent fast-forward; always create a merge commit (used with merge, not rebase).
--force-with-leasePush a rebased branch safely; aborts if the remote has new commits since your last fetch.
--update-refsAuto-update branch pointers for any branches pointing at rebased commits; useful in a stack.
--rebase-mergesPreserve merge commits during interactive rebase.
# Push a rebased branch without clobbering someone else's push
git push --force-with-lease origin feature/auth

Common 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 --abort fully restores the pre-rebase state including the branch pointer; it is always safe to run if you are stuck.
  • git rebase --skip drops 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> or git pull --rebase.