Git & Command Line · Lesson 7 of 12
Rebase and a Clean History
Learn git rebase and interactive rebase: update a branch onto main, squash and reword commits with fixup, and follow the golden rule of rebasing safely.
- Intermediate
- 16 min read
- 4 objectives
Before this lessonLesson 6: Resolving Merge Conflicts
What you will learn
- Explain what rebase does to commits
- Rebase a feature branch onto main
- Squash, reword and reorder with rebase -i
- Know when rebasing is unsafe
Your Progress
0 of 12 lessons 0%
- Lessons0 / 12
- Completed0
- Est. time left~ 3 hours
Create a free account to keep your progress on every device.
Tip: pressing Next marks this lesson complete automatically.
Merging keeps every commit exactly as it happened, including "fix typo" and "oops" commits and a merge commit every time you sync with main. Rebase is the other tool: it rewrites your branch so it looks as if you started from the latest main and made tidy, deliberate commits. Reviewers love it; used carelessly it confuses teammates. This lesson shows both sides.
What rebase actually does
git rebase main takes the commits that are on your branch but not on main, sets them aside, moves your branch to the tip of main, and then replays each commit one by one on top. The changes are the same, but every replayed commit gets a new hash, because its parent changed. That is the key fact behind every rebase rule.
Before: After git rebase main:
A---B---C feature A'--B'--C' feature
/ /
D---E---F main D---E---F mainUpdating a feature branch
Our feature branch has three commits, and meanwhile someone pushed "Update footer" to main:
git switch feature
git rebase main
git log --oneline --graph --allRebasing (1/3)Rebasing (2/3)Rebasing (3/3)Successfully rebased and updated refs/heads/feature. * aea1c3e (HEAD -> feature) Style search box * 85d153e Fix typo * 473b67a Add search box * d72d1c1 (main) Update footer * 49e968f Initial commit
A straight line, no merge commit. When this branch is merged, it can fast-forward. In practice most people fetch first: git fetch then git rebase origin/main, or simply git pull --rebase.
Conflicts during a rebase
Because commits are replayed one at a time, you might resolve a conflict per commit. The loop is always the same:
# Git stops: CONFLICT in search.js
# ...edit the file, remove markers...
git add search.js
git rebase --continue # replay the next commit
# or
git rebase --skip # drop this commit entirely
git rebase --abort # give up, branch goes back to how it wasInteractive rebase: edit your own history
git rebase -i opens a to-do list of your commits in your editor. You change the word at the start of each line to tell Git what to do:
git rebase -i main # or: git rebase -i HEAD~3pick 473b67a Add search box
pick 85d153e Fix typo
pick aea1c3e Style search box
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = meld into previous commit, combine messages
# f, fixup = meld into previous commit, discard this message
# d, drop = remove commit"Fix typo" is noise. Change its pick to fixup, save and close the editor:
pick 473b67a Add search box
fixup 85d153e Fix typo
pick aea1c3e Style search boxRebasing (2/3)Rebasing (3/3)Successfully rebased and updated refs/heads/feature. * 6cf7fab (HEAD -> feature) Style search box * 6f97ce0 Add search box * d72d1c1 (main) Update footer * 49e968f Initial commit
Two clean commits, each one meaningful on its own. You can also reorder lines to reorder commits, or delete a line to drop a commit.
fixup commits and autosquash
Even better: when you notice a mistake later, create the fix already labelled for its target, and let Git arrange the to-do list for you:
git commit --fixup 473b67a # message: "fixup! Add search box"
git rebase -i --autosquash main # the fixup line is pre-placed
git config --global rebase.autoSquash true # make it the defaultThe golden rule
Never rebase commits that other people have based work on. Rebasing creates new commits and abandons the old ones. If a teammate already pulled the old ones, their history and yours now disagree, and they get duplicated commits and painful conflicts.
- Rebasing your own local, unpushed branch: always fine.
- Rebasing your own pushed feature branch that nobody else uses: fine, then push with
git push --force-with-lease. - Rebasing
mainor any shared branch: don't.
Merge or rebase?
Both are valid, and many teams combine them: rebase locally to tidy and update your branch, then merge the pull request (often with GitHub's Squash and merge or Rebase and merge button). Merge commits are honest about what happened; rebased history is easier to read and to git bisect. Follow whatever your team has agreed, and if something goes wrong mid-rebase, git reflog still has your original commits.
Recap
- Rebase replays your commits on a new base; every replayed commit gets a new hash.
git rebase main(orpull --rebase) keeps a feature branch current without merge commits.rebase -ilets you squash, fixup, reword, reorder and drop commits.--continue,--skipand--abortcontrol a paused rebase.- Only rewrite history nobody else depends on, and push it with
--force-with-lease.
# Write your solution here
Finished reading? Mark this lesson complete to track your progress.
