Merge, Squash, or Rebase
The green button hides three different operations that leave three different histories on your main branch, and most teams pick by accident. See what each one writes, then meet the protection rules that decide who may press it.
Worth reading first: Replaying Commits Somewhere Else
The green button hides three different operations that leave three different histories on your main branch, and most teams pick by accident. See what each one writes, then meet the protection rules that decide who may press it.
The green button hides three operations
The dropdown next to Merge pull request offers Create a merge commit, Squash and merge, and Rebase and merge. They are three different Git commands, and the choice is permanent — it is what lands on main.
The branch, as it was written
- wip
- fix the thing
- actually fix it
- lint
Four honest work-in-progress commits. This is what a real branch looks like before anybody tidies it.
main, afterwards — newest first
- Merge pull request #483 from fix/login
- lint
- actually fix it
- fix the thing
- wip
- Add the settings page
- Keeps
- Every commit, with its original hash, plus a record that a branch existed at all.
- Costs
- main's history is now four commits longer, and four of them are noise.
- git bisect
- Bisect can land on "wip", which does not build. Every intermediate commit is now a candidate, and half of them were never meant to be seen.
- Undoing it
- One revert of the merge commit undoes the whole branch — but it needs -m 1 to say which parent was mainline, and re-merging that branch later is genuinely awkward.
Cycle through those three and read the four rows underneath. The differences are not aesthetic. They change what git bisect can find, what a revert costs, and whether the commits on main are the same objects that were reviewed and tested.
Create a merge commit keeps everything
This is git merge --no-ff. Every commit from the branch arrives with its original hash, and a merge commit records the join.
* 9f3c1a2 Merge pull request #483 from you/fix/login|\| * 4b8e0d7 lint| * 8a2c5f1 actually fix it| * 2c7a91f fix the thing| * 7e4d9b3 wip|/* 1a5e8c3 Add the settings pageLong-lived branches with commits that were each written deliberately. Also for projects where knowing what was developed together matters.
Every work-in-progress commit is now on main forever. Bisect can land on "wip", which does not build.
One revert of the merge commit undoes the branch — but needs -m 1, and re-merging that branch later is genuinely awkward.
Squash and merge turns a branch into one commit
Every change on the branch is combined into a single new commit on main. The individual commits are not merged; they stay on the branch, which is usually then deleted.
This is the most popular option on GitHub by a wide margin, and the reason is worth stating plainly: every commit on main builds and passes. Bisect becomes reliable, reverting is one commit with no flags, and the log reads as a list of features rather than a list of afternoons.
Quote CSV fields per RFC 4180 (#483) Values containing commas, quotes, or newlines produced malformedrows and aborted the download. Fixes #482.The cost is real: a carefully staged five-commit story becomes one blob. Which is why people who write good commit messages tend to dislike this button, and why the honest answer is that it depends on whether your team's commits are worth keeping.
Rebase and merge replays with no merge commit
Each commit from the branch is replayed onto main, in order, with no merge commit. The history is perfectly linear and every individual commit is preserved.
It sounds like the best of both and it has the sharpest edge. Every replayed commit gets a new hash, so what lands on main is not what was reviewed and not what CI tested. It also loses any record that these commits were one unit, which means there is no single thing to revert.
Teams that keep every commit clean and buildable, and genuinely want a linear history with no merge commits.
New hashes for every commit, and no marker showing where the branch began or ended.
There is no one commit to revert. You revert a range, and you work out the range yourself.
A practical rule for choosing, if your team has not: use squash unless somebody can articulate why the individual commits are worth keeping on main. Most branches are one logical change made messily, and squash is the honest representation of that.
Branch protection decides who may press it
By default anyone with write access can push directly to main, and every process described in the last three chapters is optional. Branch protection rules — or rulesets, the newer and more flexible form — are what make it real.
Direct pushes to main are rejected. This is the one that turns "we review things" into a fact.
One or two. Two is the standard on anything where a mistake is expensive.
A new push clears existing approvals. Without it, somebody can approve a small change and then push a large one.
Name the checks that must be green. A check not named here can be red and the merge is still allowed.
The branch must include the latest main before merging. Prevents two individually-passing pull requests from breaking main together.
Every review thread must be resolved. Stops comments being merged past.
Nobody can rewrite main's history. On by default with protection, and it should stay on.
And afterwards: delete the branch. GitHub offers a button and a setting to do it automatically, and the commits are safely in main either way. If you need it back, the Restore branch button on the pull request works for months.
$ gh pr merge 483 --squash --delete-branch$ gh pr merge 483 --auto --squash # merge as soon as everything goes green # On your own machine afterwards$ git switch main$ git pull$ git fetch --prune # drop remote-tracking refs for deleted branchesA repository where the process is real, not aspirational
- ✓main protected: no direct pushes, no force pushes
- ✓At least one required approval, and stale approvals dismissed on push
- ✓The checks that actually matter marked required — a red optional check gates nothing
- ✓Conversation resolution required, so comments cannot be merged past
- ✓Only the merge strategy you have chosen left enabled
- ✓Automatically delete head branches, so the branch list stays readable
Key takeaways
- The green button is three different Git operations and the choice is permanent.
- Create a merge commit keeps every commit and its hash, plus a record of the join — and puts "wip" on main forever.
- Squash and merge makes one commit, so every commit on main builds and bisect is reliable.
- The generated squash message contains your "wip" and "lint" subjects. Edit it before confirming.
- Rebase and merge is linear and preserves commits, but gives every one a new hash and leaves nothing single to revert.
- Default to squash unless somebody can say why the individual commits are worth keeping.
- Disable the strategies you do not use, so the decision is made once.
- Branch protection is what turns an agreed process into an enforced one.
- A status check that is not marked required can be red and the merge still allowed.
- Auto-merge makes strict rules bearable; it merges nothing that was not already mergeable.
Quick check
Answer these to unlock the next chapter — 3 of 4 to pass. You can retake it anytime.
Answer every question to check.
Make a free account to read on
Every chapter is free — an account is how your progress, XP, and streak follow you from your laptop to your phone, and how you show up on the leaderboard. No payment, no trial.