Skip to content

BUG: on a non-default-branch workflow_dispatch, generate_git_patch bases the patch on the default branch instead of GITHUB_SHA #52161

Description

@sg650

Summary

When a workflow is workflow_dispatch-ed from a ref that is not the default branch, generate_git_patch bases the patch on merge-base(defaultBranch, agent-branch) rather than on the dispatched commit (GITHUB_SHA), which it has already resolved and logged. Two things follow:

  1. The patch spans the whole dispatched branch, not the agent's work. If the dispatched ref is 13 commits ahead of the default branch, the agent's one-commit fix becomes a 14-commit patch.
  2. On a partial clone it cannot be generated at all. Diffing from that older base needs base-side blobs the checkout never fetched, so git falls back to a lazy promisor fetch, which is unauthenticated (persist-credentials: false) and fails — and the failure is reported as Branch 'X' does not exist locally.

Both symptoms are invisible on a default-branch dispatch, because there merge-base == GITHUB_SHA and neither triggers. That is why this can sit unnoticed: it only appears when you dispatch a workflow from a branch to test it.

Trace

[generate_git_patch] Starting patch generation: mode=full, branch=agent-fix/example, defaultBranch=main
[generate_git_patch] Environment: cwd=/home/runner/work/<repo>/<repo>, GITHUB_SHA=<dispatched-sha>
[generate_git_patch] Strategy 1: Using pinned SHA <head-sha> (branch: agent-fix/example)
[generate_git_patch] Strategy 1 (full): Computing merge-base with main (ignoring any stale origin/agent-fix/example)
[generate_git_patch] Strategy 1 (full): origin/main exists locally
[generate_git_patch] Strategy 1 (full): Computed merge-base: <old-sha>
[generate_git_patch] Strategy 1: Resolved baseRef <old-sha> to SHA <old-sha>
[generate_git_patch] Strategy 1: Found 13 commits between <old-sha> and <head-sha>
[generate_git_patch] Strategy 1: Branch 'agent-fix/example' does not exist locally - ERR_SYSTEM: remote: Invalid username or token. Password authentication is not supported for Git operations.

Found 13 commits is the giveaway: the agent made one commit. The other 13 are the dispatched branch's own history. git rev-list --count $(git merge-base origin/main HEAD)..HEAD in that repo returns exactly 13, confirming the base is the merge-base and not GITHUB_SHA.

Why it fails outright on a partial clone

The error handed back to the agent names the object it could not fetch:

Pinned SHA <head-sha> failed to generate patch: ERR_SYSTEM: remote: Invalid username or token.
Password authentication is not supported for Git operations.
fatal: Authentication failed for 'https://github.com/<org>/<repo>.git/'
fatal: could not fetch <sha> from promisor remote

That object is a blob, and it resolves to:

<sha> == git rev-parse <merge-base>:.github/aw/actions-lock.json

i.e. the base-side copy of a file the dispatched branch modified — in this case gh-aw's own actions-lock.json, which any repo upgrading gh-aw on a branch will have changed.

The setup that exposes it:

  1. The gh-aw checkout is fetch-depth: 1, so only the checkout commit's blobs are local.
  2. A workflow step fetches the commit graph cheaply with git fetch --filter=blob:none --tags --unshallow origin. This is a normal thing to do for git log / git tag --contains access, and it leaves origin marked a promisor remote (remote.origin.promisor=true, remote.origin.partialclonefilter=blob:none) permanently in .git/config.
  3. Basing the patch on the older merge-base requires that commit's blobs for every changed path. They were never fetched.
  4. Git lazily fetches them from the promisor remote. gh-aw's checkout is persist-credentials: false, so that fetch is unauthenticated and fails.

If the base were GITHUB_SHA, step 3 would need no absent blobs at all — the checkout commit's tree is fully local — so the correct base choice also removes the partial-clone failure as a side effect.

The error message is separately wrong

Strategy 1: Branch 'agent-fix/example' does not exist locally - ERR_SYSTEM: remote: Invalid username or token.

The branch did exist locally; the same trace resolved its merge-base and counted its commits two lines earlier. An auth failure while hydrating a blob is reported as a missing local branch, which sends you looking at refs, branch naming, and preserve-branch-name — none of which are involved. This is what makes the underlying problem expensive to find rather than merely annoying.

Expected

  • When GITHUB_SHA is not an ancestor of the default branch (the general case for a non-default-ref workflow_dispatch), base the patch on GITHUB_SHA. gh-aw already resolves and logs it one line above the merge-base computation. This makes the patch contain the agent's commits only, and needs no objects beyond the checkout.
  • Determine branch existence from local refs only — git rev-parse --verify --quiet refs/heads/<branch> — and never report a network/auth error as "does not exist locally".
  • Optionally, when a git call fails on a partial clone, say so: "repository is a partial clone (remote.origin.promisor=true) and the lazy blob fetch is unauthenticated" would be self-diagnosing, since gh-aw knows it emitted persist-credentials: false.

Environment

  • gh-aw v0.86.2; also observed on v0.86.1
  • engine: copilot, strict security, Linux runner
  • checkout: gh-aw defaults (fetch-depth: 1, persist-credentials: false), plus a workflow step running git fetch --filter=blob:none --tags --unshallow origin
  • create-pull-request safe output, preserve-branch-name: true, mode=full
  • Reproduced on every non-default-branch dispatch (3/3); never on a default-branch dispatch, where the patch generates normally

Note

This supersedes #52153, which I filed with an incorrect root cause (I read it as a v0.85.4 → v0.86.1 regression; the A/B was confounded — the passing arm was a default-branch dispatch, the failing arms were branch dispatches). Closed in favour of this one.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions