Skip to content

Squash merge destroys every record on the branch — measured 0/20 survival #60

Description

@MongLong0214

bench/results/deterministic-20260727T083941Z.md §2:

operation survived / total
interactive-rebase 20 / 20
rebase-onto 20 / 20
cherry-pick 20 / 20
filter-branch 20 / 20
squash-merge 0 / 20

Reproduced independently, outside the harness:

3 records on a feature branch
git merge --squash feat && git commit -m 'squash: bring in feat'
→ 0 records in HEAD, 0 in the entire history

Why this one matters more than the others

"Squash and merge" is a button in the GitHub UI and the default merge strategy at many organisations. Rebase and cherry-pick preserve records because they preserve messages one-to-one; squash collapses N messages into one that the merger writes, and the trailers go with the messages that no longer exist.

The notes mirror does not save it either — notes attach to a SHA, and squash produces a new one.

So the product's central claim — decision history is bound to git and survives normal workflows — is false for a workflow a large fraction of users have configured as their default. That is not a bug in a corner; it is a limitation that belongs on the README before anyone adopts the tool on that basis.

Directions, none obviously right

  1. Detect and refuse. A pre-merge hook that fails when squashing commits carrying records. Honest, and annoying enough that people will disable it.
  2. Fold the trailers. Concatenate records from the squashed commits into the squash message, with Provenance: inherited <sha> — the vocabulary already has the word for this. Produces one commit carrying many records, which validate may not accept as-is.
  3. Document it and stop claiming survival. Cheapest, and possibly correct: a tool that binds records to commits cannot follow an operation that deletes the commits.

(2) is the only one that preserves the claim. Whether it should is a design decision, not an implementation detail — the resulting record set says one commit made decisions that were actually made across several, and that may be a worse lie than losing them.

Decide the direction before writing code. Whatever is chosen, §2's number goes in the README either way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions