Skip to content

Stop hook: a branch pushed from an add_repo clone always reads as unpushed #217

Description

@bdelanghe

Fallout surfaced by #215 (issue #214). The scope fix there was correct; it exposed a pre-existing assumption in the per-repo predicate that is wrong for the clones add_repo produces.

Symptom

At Stop, in a session that used add_repo:

/workspace/verbspec: Branch 'claude/next-jybxja' has 1 unpushed commit(s) and no remote branch.
Please push these changes to the remote repository.

The branch was pushed. Its PR was reviewed and squash-merged. The remote branch still exists.

Mechanism

add_repo instructs git clone --depth 1, which writes a single-branch fetch refspec. Measured in /workspace/verbspec while the message above was firing:

remote.origin.fetch              = +refs/heads/main:refs/remotes/origin/main
branch.<branch>.merge            = refs/heads/<branch>        (push -u DID set tracking)
refs/remotes/                    = origin/HEAD, origin/main   (and nothing else)
git ls-remote --heads origin <branch>  ->  the branch EXISTS on the remote

The hook decides "is this pushed?" with git rev-parse origin/$current_branch — a purely local remote-tracking ref. Under a single-branch refspec that ref is never created, no matter how many successful pushes happen. So the hook falls through to upstream=origin/HEAD, reports "no remote branch", and counts the commit as unpushed.

Why it matters now

Before #215, /workspace checkouts were never examined, so this could not fire. Now every session that adds a repo mid-session and pushes a branch will hit it — permanently, including immediately after a clean push, and forever after the PR merges.

That is the cries-wolf mode this repo already names as worse than no hook: "A hook that cries wolf on every merge is worse than no hook: it teaches you to ignore the one time it is right." The existing infra#112 exclusion does not help — it covers a local branch reset onto the merged default branch, not a branch whose remote-tracking ref was never fetched.

Proposed fix

Narrow, and only on the path that is already failing. Where origin/$branch does not resolve but branch.$name.merge is configured, ask the remote before concluding anything:

git ls-remote --heads origin "$branch"

and compare the returned sha against HEAD / containment. A network call lands only in the single-branch-clone case, not on every Stop.

Worth deciding alongside: whether the discovery in #215 should instead fetch the branch ref for /workspace clones so the local ref exists in the first place. The ls-remote route is cheaper and does not mutate the checkout.

Acceptance

  • A branch pushed from a --depth 1 single-branch clone does not report as unpushed.
  • Genuinely unpushed work in such a clone still reports.
  • A test covers the single-branch-refspec shape specifically, and fails without the fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions