skip to content

On GitHub, how do the squash, merge commit, and rebase merge buttons differ in what they leave on the base branch?

level: middleimportance: must knowfreq 80%

answer

  1. Three buttons, one repository policy
  2. Count the parents each option leaves
  3. One of them collapses everything into one commit
  4. One of them rewrites every SHA
  5. Merge commit keeps SHAs; squash and rebase do not

basics

~20 s

A merge commit keeps every PR commit and adds a two-parent commit. Squash and merge replaces them with one new commit. Rebase and merge replays them as new commits with new SHAs and no merge commit.

solid answer

~50 s

GitHub offers three merge buttons and a repository owner chooses which are enabled. - **Create a merge commit** joins the head branch into the base with an explicit merge commit that has two parents, even when a fast-forward would have been possible. Every commit from the pull request stays on the base branch with its original SHA. - **Squash and merge** collapses the whole pull request into a single new commit on the base branch. The individual commits never land, so the head branch is not an ancestor of the base afterwards. - **Rebase and merge** replays each pull request commit onto the base tip. GitHub rewrites the committer information, so the commits get new SHAs, and no merge commit is created. The practical trade is auditability versus a clean, linear log: merge commits preserve the real shape of the work, squash gives one revertable unit per pull request, rebase gives linear history but loses the original commit identities.

code

text · 11 lines
text
start:            A---B         (main)
                       \
                        E---F   (feature)

merge commit:     A---B-------M    M has parents B and F; E and F kept
                       \     /
                        E---F

squash:           A---B---S        S is one new commit; E and F not on main

rebase merge:     A---B---E'--F'   copies of E and F with new hashes

go deeper

for a junior

Be able to name the three buttons GitHub shows and say, in one sentence each, what lands on the base branch. Knowing that squash produces exactly one commit is the minimum here.

for a middle

Explain the mechanics: parent counts, whether commit hashes survive, and why GitHub creates a merge commit even when a fast-forward was possible. Expect to be asked which options a linear-history requirement rules out.

for a senior

Show judgment about the consequences you have lived with: rollback granularity, bisecting a squashed log, stacked pull requests breaking after a squash, and pairing squash with automatic head-branch deletion.

for a principal

Own the policy question. Argue for one strategy per repository, encoded by disabling the other buttons, and explain how the choice interacts with linear-history rules, release tooling and incident rollback across many repositories.

## The choice is a repository policy, not a personal preference When you open the merge button on a GitHub pull request you may see up to three options: *Create a merge commit*, *Squash and merge*, and *Rebase and merge*. Which of them appear is a repository setting — an admin ticks *Allow merge commits*, *Allow squash merging*, and *Allow rebase merging* independently, and at least one must stay enabled. That is why this question is really about what kind of main-branch history a team has agreed to keep, and it is the classic split between what Git can do and what GitHub lets you do. ## Create a merge commit This produces a commit with two parents: the previous tip of the base branch and the tip of the pull request branch. GitHub always creates that commit, even when the base branch has not moved and a fast-forward would have been possible. The consequences: - Every commit authored on the pull request branch is now reachable from the base branch, with its original commit hash intact. - The merge commit itself is a durable record that says "these commits arrived together, through this pull request". - The history is not linear, so reading the base branch log without a graph view can be confusing, and a repository that requires linear history cannot use this option at all. ## Squash and merge GitHub takes the combined diff of the pull request and writes it as a single brand-new commit on the base branch with one parent. The pull request's own commits are never added to the base branch's ancestry — GitHub still marks the pull request as merged, because the merged state is recorded by GitHub, not inferred from Git ancestry. The default message for that commit is configurable per repository: the pull request title, the title plus the description, or the title plus the list of squashed commit messages. Teams that squash usually also enable automatic deletion of the head branch, because the branch no longer carries anything the base branch needs. Squashing is popular because it makes one pull request equal one commit: the log of the base branch reads as a list of shipped changes, each one individually revertable. The cost is that fine-grained authoring history — the "fix typo", but also the genuinely useful intermediate steps — is discarded, and the head branch is not an ancestor of the base afterwards, which matters if anyone keeps working on that branch or has stacked another pull request on top of it. ## Rebase and merge GitHub replays each commit of the pull request onto the current tip of the base branch and then moves the base branch forward to the result. No merge commit is created, and the base branch stays linear. Crucially, GitHub updates the committer information while replaying, so the resulting commits always have new hashes even if the base branch never moved. The original author is preserved; the committer becomes the person who clicked the button. This is the option people misunderstand most often. Candidates frequently claim the commits are "kept as-is" — they are not; they are copies. Anyone who had the original commits checked out locally now holds commits that look identical but are different objects. ## Interactions worth knowing - **Linear history.** If a repository requires linear history, merge commits are disallowed and only squash or rebase merging can be used. - **Signed commits.** Commits GitHub itself creates — squash commits, merge commits, and rebase-merge copies made through the web interface — are signed with GitHub's own key and show as verified. Locally signed commits keep their own signature only in the merge-commit case, since squash and rebase produce new objects. - **Stacked work.** A pull request based on another pull request's branch survives a merge-commit merge most gracefully, because the parent's commits keep their identities. - **Reverting.** With squash merging, reverting a change means reverting exactly one commit, which is why teams that value fast rollback often standardise on it. ## How to answer the question Say what each button writes, then state the trade-off rather than declaring a winner. A good answer sounds like: "Merge commits preserve the true shape and are the safest under stacked work; squash gives a clean, one-commit-per-change log and trivial reverts; rebase gives a linear log but silently rewrites the commits. Pick one per repository, encode it by disabling the other two, and pair squash with automatic head-branch deletion."

  • After a squash merge, why does GitHub still show the pull request as merged when its commits are absent from main?
    The merged state is stored by GitHub, not derived from Git ancestry. GitHub records that it performed the merge operation for that pull request and marks it merged. Git, meanwhile, only sees one new commit on the base branch, so the head branch is not an ancestor of the base.
  • Where does a team encode a merge-strategy decision so it is actually enforced?
    In the repository's pull request settings: enable only the merge methods you want and disable the rest, so the unwanted buttons never appear. Requiring linear history in a ruleset further blocks merge commits. A written convention alone is not enforcement — the button that exists is the policy.
  • What is the default commit message for a GitHub squash merge, and can it be changed?
    It is configurable per repository. Options include the pull request title alone, the title plus the description, and the title plus the list of squashed commit messages. Teams that want traceability usually pick a form that includes the pull request title, since it carries the pull request number.

saying these in an interview costs you the question

  • Says rebase and merge keeps the original commit SHAs
  • Thinks squash merging leaves the branch's commits in main's history
  • Believes each developer picks the merge method freely
  • Claims GitHub fast-forwards when you choose create a merge commit
  • Treats merge commits as pure noise with no information value

context