Andrew Mercer
on this page

04 · Rebase

← Overview · Prev: Everyday workflow · Next: Undo and recovery →

Rebase replays your commits on top of a new base, giving a clean, linear history.

Before:  main: A - B - C - D          After:  main: A - B - C - D
                      \                                          \
         feature:      E - F                  feature:            E' - F'

E' and F' contain the same changes as E and F but have new SHAs, because their parent changed.

What git does

  1. git fetch origin — download the remote state (working files untouched).
  2. Find your commits: those reachable from HEAD but not from origin/main.
  3. Temporarily reset your branch to origin/main.
  4. Re-apply each of your commits in order, creating new commits.
  5. If a replay conflicts, stop and let you resolve it.

The everyday sequence

git fetch origin
git rebase origin/main
# conflict? edit files, then:
git add <resolved-files>
git rebase --continue          # or: git rebase --skip / git rebase --abort
git push --force-with-lease    # required after rebasing an already-pushed branch

git-adm: git-adm rebase (--continue, --abort, --skip, --explain). git-adm push detects a diverged branch after a rebase and uses --force-with-lease automatically.

Rules of thumb

  • Never rebase a branch other people have checked out. Rewriting SHAs forces everyone to reconcile. Your own feature branches are fine.
  • Use --force-with-lease, never bare --force: it refuses to overwrite commits you have not seen.
  • Rebase before you push the first time, or before the PR is reviewed; avoid rewriting history mid-review unless your team is fine with it.
  • During conflict resolution, git add every resolved file (including things like a version file); otherwise the rebase can commit a deletion.
  • Set pull.rebase=true and rebase.autoStash=true (setup).

Rebase vs merge

Merge Rebase
History Non-linear; merge commits record joins Linear
Original commits Preserved as-is Rewritten (new SHAs)
Conflict handling Resolve once Possibly once per replayed commit
Safe on shared branches Yes No
Best for Integrating long-lived shared branches Tidying your own branch before a PR

Squash your branch into one commit

git rebase -i origin/main
# in the editor: keep the first "pick", change the others to "squash" (or "fixup" to discard their messages)

Auto-squash workflow:

git commit --fixup <sha>            # mark a commit as a fix for <sha>
git rebase -i --autosquash origin/main

git-adm push offers to squash on the first push when there is more than one commit.

Interactive rebase commands

pick keep · reword edit message · edit stop to amend · squash meld into previous (keep message) · fixup meld into previous (drop message) · drop delete the commit · reorder lines to reorder commits.

Move a branch onto a different base

git rebase --onto <new-base> <old-base> <branch>

Example: feature-b was branched from feature-a, which was squash-merged into main:

git rebase --onto main feature-a feature-b

Undo a rebase

git reflog                       # find the entry from just before the rebase started
git reset --hard <sha>           # or: git reset --hard ORIG_HEAD (right after finishing)

git-adm: git-adm undo. More in Undo and recovery.

Reading

  • https://git-scm.com/book/en/v2/Git-Branching-Rebasing
  • https://www.warp.dev/terminus/undo-a-git-rebase
  • Video: "Learn Git Rebase in 6 minutes" (YouTube id f1wnYdLEpgI)