In Git, what does git merge --squash do and what history does it leave behind?
answer
- It stops before committing
- Look at the parent count
- No MERGE_HEAD is recorded
- Git does not consider the branch merged
basics
~20 sgit merge --squash stages the other branch's combined changes but makes no commit, does not move HEAD and records no MERGE_HEAD. The commit you make afterwards has a single parent, so the branch's individual commits and the merge link never enter history.
solid answer
~50 s`git merge --squash <branch>` computes the same merge result as a normal merge and puts it in the index and working tree, then stops. It deliberately does not commit, does not move `HEAD`, and does not write `MERGE_HEAD`, so the commit you create yourself has exactly one parent — your branch's previous tip. Git pre-fills a suggested message in `.git/SQUASH_MSG` listing the squashed commits. The result is one commit carrying the whole change, with no link back to the branch. That is the point (a tidy single entry per feature) and also the cost: the individual commits are gone from this branch's history, `git branch --merged` will not report the branch as merged, and a later merge of the same branch will use the old merge base and try to re-apply work that is already in.
code
console · 6 lines$ git switch main
$ git merge --squash feature
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
$ git commit
[main 4c9a1f2] Add rate limiting to the API gatewaygo deeper
Recall the two-step nature: --squash stages the combined change, then you run git commit yourself, and the result is one ordinary commit.
Explain the topology precisely — one parent, no MERGE_HEAD, message suggested in .git/SQUASH_MSG — and contrast it with fast-forward and --no-ff.
Demonstrate awareness of the aftermath: branch --merged stays silent, re-merging the same branch replays work, and bisect and blame granularity are gone.
Be able to argue when collapsing history is worth the loss, and to set a repository convention for what happens to a branch once it has been squashed in.
## What the command does `git merge --squash <branch>` runs the normal merge machinery — same merge base, same three-way merge, same conflicts if there are any — and then stops short of committing. Specifically it produces the working tree and index state a real merge would have produced, but it does **not** create a commit, does **not** move `HEAD`, and does **not** record `MERGE_HEAD`. You finish the operation yourself: `git merge --squash feature` then `git commit` Git writes a suggested commit message into `.git/SQUASH_MSG`, listing the commits that were squashed, and your editor opens with it pre-filled. Because `--squash` deliberately hands the commit step to you, combining it with `--commit` is rejected. ## The resulting topology The commit you create has **one parent**: the previous tip of the branch you are on. Nothing in the object graph records that the content came from `feature`. Compare the three outcomes for the same feature: - **Fast-forward** — the feature's commits become part of the branch, unchanged, in a straight line. No new object. - **Merge commit** — a two-parent commit joins the branch's history to yours; every original commit is reachable through the second parent. - **Squash** — one brand-new commit whose tree matches the merge result, with a single parent. The original commits are not reachable from this branch at all. In `git log --graph` a squash looks exactly like an ordinary hand-written commit. That is the appeal: one line of log per feature, with no branch bubbles and no intermediate "fix typo" commits. ## What is genuinely lost The original commits are not destroyed — they remain reachable from the feature branch ref for as long as it exists, and via its reflog for a while after. But they are not part of the branch you squashed into, so: - `git bisect` on the target branch treats the whole feature as one step; if the feature is large, bisect stops at "somewhere in these 900 lines". - `git blame` attributes every touched line to the squash commit, losing the per-change rationale and the original authorship of individual commits. - Multi-author work collapses onto one author, with co-authors only surviving if you write trailers into the message. ## The re-merge trap This is the consequence interviewers probe most. Because the squash commit has no parent link to the feature branch, Git's notion of the merge base between the two branches does not move. `git branch --merged main` will not list the feature branch even though its content is in `main`. If the branch stays alive and is merged again later, Git starts from the *original* fork point and tries to apply the branch's changes on top of a branch that already contains an equivalent result — producing spurious conflicts or duplicated hunks. The practical discipline is: after squashing, either delete the branch, or reset it onto the target branch so it restarts from the squashed state, rather than continuing to add commits on the old base. ## Conflicts still happen `--squash` is not a conflict-avoidance tool. The same three-way merge runs, so the same conflicts appear and must be resolved before you commit. What differs is only what gets recorded afterwards. ## When squashing is the right call Squashing suits branches whose intermediate commits have no archival value — a day of exploratory commits, review-fixup churn, or a single logical change split only for convenience. It suits repositories that want one commit per unit of work in the log. It suits long-lived, carefully curated branches badly: if each commit is a meaningful, individually revertible step, collapsing them throws away exactly the information the author invested in. It also suits shared long-lived branches badly, because of the re-merge trap above. ## Distinguishing it from neighbours A squash merge is not a fast-forward (which creates nothing) and not `--no-ff` (which creates a two-parent commit). It is also not the same as collapsing commits during an interactive rebase: that rewrites the branch's own commits in place, whereas `--squash` leaves the source branch untouched and writes one new commit on the target. If asked to compare, name the parent count and the effect on `git branch --merged` — those two facts separate the options cleanly.
- Why does Git not create the commit for you when you pass --squash?Because the operation is explicitly "prepare the result, let the author describe it": Git leaves the index staged, writes a suggested message to `.git/SQUASH_MSG`, and expects `git commit`. Passing `--commit` alongside `--squash` is rejected rather than silently honoured, so the single-parent commit is always authored deliberately.
- How does squash merging affect git bisect and git blame later?Both lose granularity. Bisect can only narrow a regression down to the whole squashed change, so a large feature becomes one indivisible step. Blame attributes every line the feature touched to the squash commit and its author, so the per-commit reasoning and original authorship are no longer visible from the target branch.
- Does --squash avoid conflicts that a normal merge would hit?No. The same merge base and the same three-way merge run, so identical conflicts surface and must be resolved before you commit. The only difference is what is recorded afterwards: one single-parent commit instead of a merge commit or a fast-forward.
saying these in an interview costs you the question
- Thinks --squash creates a merge commit with two parents
- Believes --squash commits automatically like a normal merge
- Claims Git records the branch as merged after a squash
- Says squashing avoids the conflicts a normal merge would hit
- Assumes squashing deletes the feature branch's original commits