Basic rebase
git rebase <base> # replay current branch's commits on top of <base>
git rebase origin/main # common case: bring branch up to date with remote mainInteractive rebase
git rebase -i <base> # opens editor to squash, reorder, edit, or drop commits
git rebase -i HEAD~3 # rewrite last 3 commitsCommon actions in the editor:
pick— keep the commit as-isreword— keep the commit, edit its messagesquash— fold into the previous commit, merging both messagesfixup— same as squash but discards this commit’s messageedit— pause rebase here so you can amend the commitdrop— remove the commit entirely
Rebase onto a different base (--onto)
git rebase --onto <newbase> <upstream> <branch><newbase>: where to plant the commits — any commit-ish (local branch,origin/main, SHA)<upstream>: the old base to rebase away from; commits between<upstream>and<branch>are what get moved<branch>: local branch being rebased
Useful when a branch was forked off a feature branch and you want to rebase it directly onto main:
git rebase --onto main feature-a feature-bConflict resolution
# When rebase stops at a conflict:
# 1. Fix the conflicting files
git add <resolved-files>
git rebase --continue
# Or skip the conflicting commit entirely
git rebase --skipStacked branches (chained PRs)
When PRs are chained (feature-b branched off feature-a, which branched off main), the tip branch already contains all the commits from the chain. Rebasing and merging the tip lands everything at once.
# 1. Preview what will be edited
git log master..HEAD --oneline
# 2. Rebase onto latest master, squash messy intermediate commits
git rebase -i master
# 3. Fast-forward merge — errors if history isn't linear
git merge --ff-only <branch>
# 4. Verify locally, then push
git push --force-with-lease # safer than --force; fails if someone else pushedKeep natural commit order
Reordering commits that depend on each other causes conflicts. If branches were chained (A into B into C), preserve that order in the rebase.
Pre-commit hook workarounds during rebase
Hooks run on every replayed commit. Two escape hatches:
# Skip hooks for just the amend step
git commit --amend --no-verify
# Skip hooks when continuing a rebase
GIT_HOOKS_PATH=/tmp/empty-hooks git rebase --continueRecovery
# Bail out mid-rebase
git rebase --abort
# Nuclear undo after rebase completes
git reflog # find pre-rebase HEAD
git reset --hard <pre-rebase-HEAD>Notes
--ff-onlyis the safety check — if it errors, your history isn’t linear yet--force-with-leaseover--force— won’t clobber a teammate’s push- Verify locally (run
git log, test the merge) before pushing