Topic 4.5
Merge Commit, Squash, or Rebase: How Pull Requests Land
In one line
Hosting services offer three ways to merge a PR. Merge commit (git merge --no-ff) keeps every commit and adds a merge commit. Squash and merge (git merge --squash) turns the whole PR into one new commit on main. Rebase and merge replays each commit onto main with new hashes and no merge commit. They give the same final code but different history, and different follow-up effects on bisect, revert, and branch cleanup.
Think of it like this
Adding a new chapter to a shared book. You can bind in all the author's drafts with a cover sheet (merge commit), retype it as one clean chapter (squash), or copy each draft page in order at the end of the book (rebase).
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Merge commit
- A commit with two parents that joins a branch into another.
- --no-ff
- Always create a merge commit, even when a fast-forward is possible.
- Squash merge
- Combine all of a branch's changes into one new commit on the target branch.
- Rebase merge
- Replay the branch's commits onto the target one by one, without a merge commit.
- Linear history
- History with no merge commits, a single line of commits.
- -X ours / -X theirs
- Merge options that resolve conflicting hunks in favour of one side, while still merging the rest.
Step by step
01One PR, three histories
Priya's coupon PR has three commits: 'Add coupon model', 'Validate expiry', and 'Fix typo'. Here is what main looks like after each merge method.
02The same three, done locally
The buttons on GitHub do roughly what these commands do. Seeing them locally makes the differences concrete.
03How each one affects later work
The choice matters most when something goes wrong later. A bad squash commit is reverted with a plain git revert <hash>, while a merge commit needs git revert -m 1 <merge> (Topic 7.4). With rebase merging, a revert means reverting several commits. Bisect on squash-merged main finds the PR at fault but not the exact commit inside it.
merge commit squash rebase
history on main all + merge 1 per PR all, linear
undo a whole PR revert -m 1 revert 1 commit revert N commits
bisect precision per commit per PR per commit
needs clean commits helpful no yes
git branch -d works yes no (use -D) no (use -D)04Strategy options: prefer one side, carefully
Sometimes a merge has many conflicts where one side is clearly right, for example syncing a generated translations branch. -X theirs resolves only the conflicting hunks in favour of the incoming branch and merges everything else normally. Don't confuse it with -s ours, which ignores the other branch's changes completely.
Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Continuing on a squash-merged branch
Priya's coupon PR is squash-merged. She keeps committing on the same branch and opens a second PR from it.
Myth vs fact
Myth
Squash merging loses work.
Fact
All the changes are in the squashed commit. Only the separate intermediate commits are dropped from main (the PR page still shows them).
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
With squash merging, the PR title becomes the commit subject, so enforce good PR titles (for example in Conventional Commits format, Topic 7.2) with a CI check. That way main's history and release notes stay clean without anyone rebasing by hand.
Remember this
- 1
Merge commit: all PR commits plus one merge commit with two parents. History shows exactly how work happened, and the PR can be reverted with one
git revert -m 1. - 2
Squash and merge: one commit per PR, so main reads like a changelog. Messy 'fix typo' commits disappear, but so does the detail of individual commits.
- 3
Rebase and merge: each PR commit replayed on top of main, giving linear history with all commits. Every commit should then build and pass tests.
- 4
All three produce the same files. They differ in history shape, which affects
git log,bisect(Topic 6.2), and reverts. - 5
After squash or rebase merging, the PR's original commits aren't on main, so
git branch -dsays 'not fully merged'. Delete the branch with-Donce you've confirmed the PR merged. - 6
Pick one default per repository (rulesets can enforce it, Topic 8.4). Many teams use squash for small PRs. Repos with carefully crafted commits often prefer merge or rebase.
Explain it without notes
Compare the three PR merge methods.
Why does git branch -d refuse after a squash merge?
Practice
Merge the same branch three ways in a test repo and compare git log --graph.
Trade-offs
- ↔
Merge commits keep the most information but make busier history. Squash is simplest for most teams but hides commit-level detail. Rebase merging gives linear, detailed history but requires disciplined commits.
Done when you can
I can explain merge, squash, and rebase merges.
I know how each affects revert and bisect.
I start a fresh branch after a squash merge.