Skip to content

checkout_pr_branch's --depth=2 fetch re-shallows the repo, breaking create_pull_request patch generation despite checkout.fetch-depth: 0 #50240

Description

@not-mksv

Summary

In the agent job, the built-in Checkout PR branch step (checkout_pr_branch.cjs) re-fetches the PR head branch with git fetch origin <head-ref> --depth=2. Running a --depth fetch against an already-complete clone writes .git/shallow and grafts history, silently undoing an explicit checkout: fetch-depth: 0.

create_pull_request then generates its patch in mode=full via git merge-base -- origin/<default-branch> <pinned-sha>. Across the graft there is no reachable common ancestor, so git exits 1 and the tool fails, deterministically, on every retry:

Fetching branch: <head-ref> from origin (depth: 2 for 1 PR commit(s))
/usr/bin/git fetch origin <head-ref> --depth=2
...
[generate_git_patch] Starting patch generation: mode=full, branch=docs/1737, defaultBranch=<default>
[generate_git_patch] Strategy 1 (full): Computing merge-base with <default>
[debug] Executing git command: git merge-base -- origin/<default> <sha>
[error] Git command failed: git merge-base -- origin/<default> <sha>
[error] Exit status: 1
[generate_git_patch] Strategy 1: Branch 'docs/1737' does not exist locally - ERR_SYSTEM: Git command failed with status 1

Version

gh-aw v0.84.3, engine copilot (CLI 1.0.77), awf 0.27.43.

Reproduction

git init up && cd up
for i in 1 2 3 4 5; do echo $i > f$i; git add .; git commit -m "c$i"; done
git branch -M develop && git checkout -b feature
for i in 6 7; do echo $i > f$i; git add .; git commit -m "c$i"; done

cd .. && git clone --no-single-branch up clone && cd clone
git fetch origin '+refs/heads/*:refs/remotes/origin/*'   # complete clone, as fetch-depth: 0 gives
git merge-base origin/develop origin/feature             # OK

git fetch origin feature --depth=2                       # what checkout_pr_branch.cjs does
git checkout feature && git checkout -b docs/1 && echo x > d && git add . && git commit -m docs

ls .git/shallow                                          # now exists
git merge-base origin/develop HEAD; echo "exit=$?"       # exit=1  <-- ERR_SYSTEM

rm .git/shallow
git merge-base origin/develop HEAD                       # OK again, no network needed

Why this is hard to recover from

Three things compound:

  1. The workflow asked for fetch-depth: 0 and the Checkout repository step honoured it. A later built-in step then re-shallows the repo, so the config is quietly overridden.
  2. The generated prompt still tells the agent [full history, all branches available as remote-tracking refs], which is no longer true at agent time.
  3. The agent cannot fix it. gh-aw removes git credentials before the agent runs and its own context block lists "Deepening a shallow clone (git fetch --unshallow)" as unsupported in private repos. So the agent burns turns retrying, then gives up via report_incomplete.

The error text also misleads: details says "No commits were found to create a pull request. Make sure you have committed your changes using git add and git commit before calling create_pull_request." The commit did exist and was valid; only the merge-base failed. That sends the agent down a "clean the tree and retry" path that cannot succeed.

Suggested fixes

Any one of these would do:

  • Skip the --depth=2 fetch when the repo is not already shallow (test -f .git/shallow), or when checkout.fetch-depth is 0. The needed objects are already present in that case.
  • If the shallow fetch is kept, drop the graft afterwards. When the clone was complete beforehand, rm .git/shallow is sufficient and needs no network.
  • Fall back in generate_git_patch when merge-base fails, for example diff against the PR base ref or the branch's own first commit, rather than returning ERR_SYSTEM.
  • Distinguish "no commits" from "merge-base unreachable" in the error details, and mention .git/shallow when it is present. It would have saved the agent several turns.

Separately: mode=full computes the merge-base against the repository default branch even when create_pull_request is called with an explicit base (here a non-default branch, permitted via allowed-base-branches). Diffing against the requested base seems more correct, and would shrink the patch on long-lived branches.

Workaround

pre-agent-steps runs after the PR checkout and before credential cleanup, so this restores things without network access:

pre-agent-steps:
  - name: Drop the shallow graft left by the PR-branch checkout
    env:
      DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
    run: |
      if [ ! -f .git/shallow ]; then
        echo "Repository is not shallow, nothing to do."
        exit 0
      fi
      rm .git/shallow
      git merge-base HEAD "origin/${DEFAULT_BRANCH}" > /dev/null

Activity

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions