Skip to content

session-end checklist: --no-merged reports rebase/squash-merged branches as undecided, forever #28

Description

@PBNZ

What happened

standard/session-end-checklist.md opens with:

  • No undecided branchesgit branch -a --no-merged: for each hit, merge it, delete
    it, or open an issue that owns it. No silent survivors.

--no-merged is an ancestry test. It asks "is this branch's tip reachable from HEAD", not
"did this change land". That distinction is invisible on merge-commit workflows and wrong on the
other two:

Merge method Branch tip after merge --no-merged verdict
Merge commit preserved as a parent correct — omits it
Rebase merge rewritten (new SHA) reports it as unmerged, permanently
Squash merge collapsed into a new commit reports it as unmerged, permanently

So on any repo that rebase- or squash-merges — both of which GitHub offers by default — the first
box on the checklist can never be cleared by the command it prescribes. Every landed branch is a
standing "hit" demanding you "merge it, delete it, or open an issue that owns it".

The failure mode isn't just noise, it's the two ways out of the noise:

  • The safe response is blocked. git branch -d uses the same ancestry test, so it refuses the
    branch. Following the checklist honestly leaves you stuck.
  • The obvious workaround is unsafe. Reaching for git branch -D because "-d keeps refusing
    and these are always merged" trains away the one safety net git offers. That habit deletes
    genuinely unmerged work the first time the assumption doesn't hold.

What you expected

The item to be clearable by the command it names, and to steer toward a check that answers the
question actually being asked — did this change land — rather than a proxy that only coincides
with it on one of the three merge methods.

Steps to reproduce

  1. Enable rebase or squash merging on a repo (both are on by default).
  2. Branch, commit, open a PR, merge it with --rebase (or --squash).
  3. git checkout main && git pull --ff-only
  4. git branch -a --no-merged → the merged branch is listed.
  5. git branch -d <branch>error: the branch '<branch>' is not fully merged.
  6. Steps 4 and 5 keep behaving this way indefinitely.

Suggested fix

Make the check content-based, and say plainly when -D is the right tool. Something like:

  • No undecided branchesgit branch -a --no-merged: for each hit, merge it, delete
    it, or open an issue that owns it. No silent survivors.
    On a rebase- or squash-merging repo this over-reports: both rewrite the commit, so a
    landed branch is not an ancestor of main and both --no-merged and git branch -d treat
    it as unmerged. Confirm the change landed by content, then force-delete:
    git diff <branch> main empty, or git show <branch> | git patch-id --stable equal to the
    merge commit's — then git branch -D <branch>. Never -D a branch that failed both checks.

Two things worth deciding beyond the wording:

  • git log main..<branch> --cherry-mark --left-right --no-merges is the more idiomatic git
    answer (it marks patch-equivalent commits with =), and unlike patch-id piping it is a single
    command. git diff is the easier one to eyeball, --cherry-mark the more precise. Either
    works; picking one keeps the checklist mechanical.
  • delete_branch_on_merge removes the remote half of this problem entirely, and is probably
    worth a line in the standard as a recommended repo setting. It leaves local branches as [gone],
    which git fetch --prune plus the above cleans up.

Blast radius

agent-collaboration.md quotes this rule verbatim ("merge it, delete it, or open an issue that
owns it — no silent survivors") when applying it to infrastructure residue, so the wording is load-
bearing in more than one place. pre-pr-checklist.md also touches branches but only asserts
"On a feature branch, not main", which is unaffected.

Environment

  • Claude Code version: Claude Code (Opus 5, 1M context), 2026-07-26
  • OS: Windows 11 Pro 26200
  • RepoKit (plugin) version: 0.5.0 — checked against main, where
    plugins/repokit/skills/repo-standard/standard/session-end-checklist.md is byte-identical to
    the 0.5.0 cache, so this is current and not already fixed.

Found via

Cleaning up after a rebase-merged PR in PBNZ/windirstat-cli, where the branch showed as unmerged
and -d refused it despite the work being on main. Worked around locally in that repo's
AGENTS.md (§ Branch hygiene, PBNZ/windirstat-cli#20), but the check belongs in the standard.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions