Skip to content

fix(ci): detach HEAD 释放本地分支名,避开 fork PR 同名冲突 #850

fix(ci): detach HEAD 释放本地分支名,避开 fork PR 同名冲突

fix(ci): detach HEAD 释放本地分支名,避开 fork PR 同名冲突 #850

Triggered via pull request May 17, 2026 02:38
@appergbappergb
opened #464
Status Success
Total duration 55s
Artifacts

pr-agent.yml

on: pull_request_target
pr_agent_job
52s
pr_agent_job
Fit to window
Zoom out
Zoom in

Annotations

10 errors
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 PR / Issue 上 \n...(truncated)\n======\n\n\nThe PR code diff:\n======\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n__new hunk__\n34 id-token: write\n35 actions: read # Required for Claude to read CI results on PRs\n36 steps:\n37 - name: Checkout repository\n38 uses: actions/checkout@v4\n39 with:\n40 fetch-depth: 1\n41 \n42 + # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n43 + # 背景:claude-code-action 在 fork PR 上会执行\n44 + # git fetch origin pull/<n>/head:<head-ref-name>\n45 + # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n46 + # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n47 + # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n48 + # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n49 + # 提前 detach 让本地分支名可以被 action 重新使用。\n50 + - name: Detach HEAD to free local branch ref\n51 + run: git checkout --detach\n52 +\n53 - name: Pick model (default sonnet, opt-in opus)\n54 id: pick_model\n55 env:\n56 COMMENT_BODY: ${{ github.event.comment.body }}\n======\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml", "output": "review:\n ticket_compliance_check: []\n estimated_effort_to_review_[1-5]: |\n 1\n relevant_tests: |\n No\n key_issues_to_review: []\n security_concerns: |\n No", "finish_reason": "stop", "main_pr_language": "yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 432, "message": "Full_response", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:45.899046+00:00", "timestamp": 1778985585.899046}}}
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 PR / Issue 上 \n...(truncated)\n======\n\n\nThe PR code diff:\n======\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n__new hunk__\n34 id-token: write\n35 actions: read # Required for Claude to read CI results on PRs\n36 steps:\n37 - name: Checkout repository\n38 uses: actions/checkout@v4\n39 with:\n40 fetch-depth: 1\n41 \n42 + # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n43 + # 背景:claude-code-action 在 fork PR 上会执行\n44 + # git fetch origin pull/<n>/head:<head-ref-name>\n45 + # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n46 + # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n47 + # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n48 + # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n49 + # 提前 detach 让本地分支名可以被 action 重新使用。\n50 + - name: Detach HEAD to free local branch ref\n51 + run: git checkout --detach\n52 +\n53 - name: Pick model (default sonnet, opt-in opus)\n54 id: pick_model\n55 env:\n56 COMMENT_BODY: ${{ github.event.comment.body }}\n======\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:37.654882+00:00", "timestamp": 1778985577.654882}}}
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 PR / Issue 上 \n...(truncated)\n======\n\n\nThe PR code diff:\n======\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n__new hunk__\n34 id-token: write\n35 actions: read # Required for Claude to read CI results on PRs\n36 steps:\n37 - name: Checkout repository\n38 uses: actions/checkout@v4\n39 with:\n40 fetch-depth: 1\n41 \n42 + # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n43 + # 背景:claude-code-action 在 fork PR 上会执行\n44 + # git fetch origin pull/<n>/head:<head-ref-name>\n45 + # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n46 + # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n47 + # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n48 + # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n49 + # 提前 detach 让本地分支名可以被 action 重新使用。\n50 + - name: Detach HEAD to free local branch ref\n51 + run: git checkout --detach\n52 +\n53 - name: Pick model (default sonnet, opt-in opus)\n54 id: pick_model\n55 env:\n56 COMMENT_BODY: ${{ github.event.comment.body }}\n======\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:35.240774+00:00", "timestamp": 1778985575.240774}}}
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 PR / Issue 上 \n...(truncated)\n======\n\n\nThe PR code diff:\n======\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n__new hunk__\n34 id-token: write\n35 actions: read # Required for Claude to read CI results on PRs\n36 steps:\n37 - name: Checkout repository\n38 uses: actions/checkout@v4\n39 with:\n40 fetch-depth: 1\n41 \n42 + # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n43 + # 背景:claude-code-action 在 fork PR 上会执行\n44 + # git fetch origin pull/<n>/head:<head-ref-name>\n45 + # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n46 + # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n47 + # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n48 + # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n49 + # 提前 detach 让本地分支名可以被 action 重新使用。\n50 + - name: Detach HEAD to free local branch ref\n51 + run: git checkout --detach\n52 +\n53 - name: Pick model (default sonnet, opt-in opus)\n54 id: pick_model\n55 env:\n56 COMMENT_BODY: ${{ github.event.comment.body }}\n======\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:33.161862+00:00", "timestamp": 1778985573.161862}}}
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 PR / Issue 上 `@claude`,确认正常路径不退化\n- [ ] 若有第二个 fork PR head ref name 与 base 不同名,确认仍正常工作\n\n\n___\n\n### **PR Type**\nBug fix\n\n\n___\n\n### **Description**\n- Detach `HEAD` in Claude workflow\n\n- Avoid fork PR branch-name collisions\n\n- Let `claude-code-action` fetch safely\n\n\n___\n\n### Diagram Walkthrough\n\n\n```mermaid\nflowchart LR\n A[\"actions/checkout workspace\"] -- \"detach HEAD\" --> B[\"free local branch ref\"]\n B -- \"safe fetch\" --> C[\"claude-code-action\"]\n C -- \"no branch collision\" --> D[\"fork PR review succeeds\"]\n```\n\n\n\n<details> <summary><h3> File Walkthrough</h3></summary>\n\n<table><thead><tr><th></th><th align=\"left\">Relevant files</th></tr></thead><tbody><tr><td><strong>Configuration changes</strong></td><td><table>\n<tr>\n <td>\n <details>\n <summary><strong>claude.yml</strong><dd><code>Detach workflow HEAD to avoid fetch conflicts</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>\n<hr>\n\n.github/workflows/claude.yml\n\n<ul><li>Adds a <code>git checkout --detach</code> step after repository checkout.<br> <li> Documents the fork-PR branch collision that breaks <code>claude-code-action</code>.<br> <li> Frees the default branch ref so the action can fetch PR heads safely.</ul>\n\n\n</details>\n\n\n </td>\n <td><a href=\"https://github.com/Open-Less/openless/pull/464/files#diff-53fec9c265fdba82268df5cd90315b8da57cce43d8e20efbf5c0bdcd1de1342e\">+11/-0</a>&nbsp; &nbsp; </td>\n\n</tr>\n</table></td></tr></tr></tbody></table>\n\n</details>\n\n___\n\n"}}, "file": {"name": "pr_description.py", "path": "/app/pr_agent/tools/pr_description.py"}, "function": "run", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 132, "message": "PR output", "module": "pr_description", "name": "pr_agent.tools.pr_description", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:30.903712+00:00", "timestamp": 1778985570.903712}}}
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action\n...(truncated)\n=====\n\nBranch: 'fix/claude-action-fork-detach'\n\nCommit messages:\n=====\n1. fix(ci): detach HEAD before claude-code-action on fork PR\n\nPR #451 (来自 fork aeoform/openless, head ref 也叫 beta) 触发 @claude 时,\nclaude-code-action 执行 `git fetch origin pull/451/head:beta` 把 PR head\n拉到本地 beta 分支,但此时 worktree 正 checkout 在 refs/heads/beta,\ngit 拒绝 fetch 到已 checkout 的分支:\n\n fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n\n修复: 在 actions/checkout 后立即 git checkout --detach,释放\nrefs/heads/<default-branch> 这个本地分支名,让 action 自己 fetch 不撞名.\n仅在 fork head ref == base ref name 的 corner case 才会触发问题,\ndetach 对其他场景无副作用.\n\n失败 run: https://github.com/Open-Less/openless/actions/runs/25978532215\n=====\n\n\nThe PR Git Diff:\n=====\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n id-token: write\n actions: read # Required for Claude to read CI results on PRs\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n with:\n fetch-depth: 1\n \n+ # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n+ # 背景:claude-code-action 在 fork PR 上会执行\n+ # git fetch origin pull/<n>/head:<head-ref-name>\n+ # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n+ # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n+ # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n+ # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n+ # 提前 detach 让本地分支名可以被 action 重新使用。\n+ - name: Detach HEAD to free local branch ref\n+ run: git checkout --detach\n+\n - name: Pick model (default sonnet, opt-in opus)\n id: pick_model\n env:\n COMMENT_BODY: ${{ github.event.comment.body }}\n=====\n\nNote that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml", "output": "type:\n - Bug fix\ndescription: |\n - Detach `HEAD` in Claude workflow\n - Avoid fork PR branch-name collisions\n - Let `claude-code-action` fetch safely\ntitle: |\n Detach `HEAD` before Claude action on fork PRs\nchanges_diagram: |\n ```mermaid\n flowchart LR\n A[\"`actions/checkout` workspace\"] -- \"detach HEAD\" --> B[\"free local branch ref\"]\n B -- \"safe fetch\" --> C[\"`claude-code-action`\"]\n C -- \"no branch collision\" --> D[\"fork PR review succeeds
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action\n...(truncated)\n=====\n\nBranch: 'fix/claude-action-fork-detach'\n\nCommit messages:\n=====\n1. fix(ci): detach HEAD before claude-code-action on fork PR\n\nPR #451 (来自 fork aeoform/openless, head ref 也叫 beta) 触发 @claude 时,\nclaude-code-action 执行 `git fetch origin pull/451/head:beta` 把 PR head\n拉到本地 beta 分支,但此时 worktree 正 checkout 在 refs/heads/beta,\ngit 拒绝 fetch 到已 checkout 的分支:\n\n fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n\n修复: 在 actions/checkout 后立即 git checkout --detach,释放\nrefs/heads/<default-branch> 这个本地分支名,让 action 自己 fetch 不撞名.\n仅在 fork head ref == base ref name 的 corner case 才会触发问题,\ndetach 对其他场景无副作用.\n\n失败 run: https://github.com/Open-Less/openless/actions/runs/25978532215\n=====\n\n\nThe PR Git Diff:\n=====\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n id-token: write\n actions: read # Required for Claude to read CI results on PRs\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n with:\n fetch-depth: 1\n \n+ # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n+ # 背景:claude-code-action 在 fork PR 上会执行\n+ # git fetch origin pull/<n>/head:<head-ref-name>\n+ # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n+ # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n+ # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n+ # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n+ # 提前 detach 让本地分支名可以被 action 重新使用。\n+ - name: Detach HEAD to free local branch ref\n+ run: git checkout --detach\n+\n - name: Pick model (default sonnet, opt-in opus)\n id: pick_model\n env:\n COMMENT_BODY: ${{ github.event.comment.body }}\n=====\n\nNote that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:26.886157+00:00", "timestamp": 177898556
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action\n...(truncated)\n=====\n\nBranch: 'fix/claude-action-fork-detach'\n\nCommit messages:\n=====\n1. fix(ci): detach HEAD before claude-code-action on fork PR\n\nPR #451 (来自 fork aeoform/openless, head ref 也叫 beta) 触发 @claude 时,\nclaude-code-action 执行 `git fetch origin pull/451/head:beta` 把 PR head\n拉到本地 beta 分支,但此时 worktree 正 checkout 在 refs/heads/beta,\ngit 拒绝 fetch 到已 checkout 的分支:\n\n fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n\n修复: 在 actions/checkout 后立即 git checkout --detach,释放\nrefs/heads/<default-branch> 这个本地分支名,让 action 自己 fetch 不撞名.\n仅在 fork head ref == base ref name 的 corner case 才会触发问题,\ndetach 对其他场景无副作用.\n\n失败 run: https://github.com/Open-Less/openless/actions/runs/25978532215\n=====\n\n\nThe PR Git Diff:\n=====\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n id-token: write\n actions: read # Required for Claude to read CI results on PRs\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n with:\n fetch-depth: 1\n \n+ # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n+ # 背景:claude-code-action 在 fork PR 上会执行\n+ # git fetch origin pull/<n>/head:<head-ref-name>\n+ # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n+ # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n+ # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n+ # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n+ # 提前 detach 让本地分支名可以被 action 重新使用。\n+ - name: Detach HEAD to free local branch ref\n+ run: git checkout --detach\n+\n - name: Pick model (default sonnet, opt-in opus)\n id: pick_model\n env:\n COMMENT_BODY: ${{ github.event.comment.body }}\n=====\n\nNote that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:24.231485+00:00", "timestamp": 177898556
pr_agent_job
Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. PR 来自 fork (`isCrossRepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 PR head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## Test plan\n\n- [ ] 合入后在 PR #451 上重新 `@claude`,确认 action\n...(truncated)\n=====\n\nBranch: 'fix/claude-action-fork-detach'\n\nCommit messages:\n=====\n1. fix(ci): detach HEAD before claude-code-action on fork PR\n\nPR #451 (来自 fork aeoform/openless, head ref 也叫 beta) 触发 @claude 时,\nclaude-code-action 执行 `git fetch origin pull/451/head:beta` 把 PR head\n拉到本地 beta 分支,但此时 worktree 正 checkout 在 refs/heads/beta,\ngit 拒绝 fetch 到已 checkout 的分支:\n\n fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta\n\n修复: 在 actions/checkout 后立即 git checkout --detach,释放\nrefs/heads/<default-branch> 这个本地分支名,让 action 自己 fetch 不撞名.\n仅在 fork head ref == base ref name 的 corner case 才会触发问题,\ndetach 对其他场景无副作用.\n\n失败 run: https://github.com/Open-Less/openless/actions/runs/25978532215\n=====\n\n\nThe PR Git Diff:\n=====\n## File: '.github/workflows/claude.yml'\n\n@@ -34,12 +34,23 @@ jobs:\n id-token: write\n actions: read # Required for Claude to read CI results on PRs\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n with:\n fetch-depth: 1\n \n+ # Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。\n+ # 背景:claude-code-action 在 fork PR 上会执行\n+ # git fetch origin pull/<n>/head:<head-ref-name>\n+ # 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref\n+ # 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,\n+ # 上面那条 fetch 会撞上\"当前已 checkout 的分支\"而失败:\n+ # fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...\n+ # 提前 detach 让本地分支名可以被 action 重新使用。\n+ - name: Detach HEAD to free local branch ref\n+ run: git checkout --detach\n+\n - name: Pick model (default sonnet, opt-in opus)\n id: pick_model\n env:\n COMMENT_BODY: ${{ github.event.comment.body }}\n=====\n\nNote that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.\n\n\nResponse (should be a valid YAML, and nothing else):\n```yaml"}}, "file": {"name": "litellm_ai_handler.py", "path": "/app/pr_agent/algo/ai_handlers/litellm_ai_handler.py"}, "function": "chat_completion", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 404, "message": "Prompts", "module": "litellm_ai_handler", "name": "pr_agent.algo.ai_handlers.litellm_ai_handler", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:21.575367+00:00", "timestamp": 177898556
pr_agent_job
action failed with error: command failed: git fetch origin --depth=20 pull/451/head:beta\n```\n\n## 根因(三连命中才会触发)\n\n1. pr 来自 fork (`iscrossrepository: true`)\n2. **fork 的 head 分支名也叫 `beta`** —— 与本仓库 base / 默认分支同名\n3. `actions/checkout@v4` 默认把 worktree checkout 到了 `refs/heads/beta`\n\n`claude-code-action@v1` 内部执行:\n\n```\ngit fetch origin --depth=20 pull/451/head:beta\n```\n\n把 pr head 拉到**本地同名分支 `beta`**(命名取自 fork 端 head ref name)。但 `beta` 已是当前 checked-out 分支,git 拒绝 fetch 到已 checkout 的分支 → 失败。\n\n## 修复\n\n在 `actions/checkout` 之后立即 `git checkout --detach`,释放 `refs/heads/<default-branch>` 这个本地分支名,让 action 自己 fetch 不撞名。\n\n仅对 fork head ref == base ref name 这个 corner case 有影响;其他场景(本仓库分支、fork 分支名不同)detach 都是无副作用的。\n\n## 改动\n\n- `.github/workflows/claude.yml`: +11 行,单 step + 注释,无其他改动。\n\n## test plan\n\n- [ ] 合入后在 pr #451 上重新 `@claude`,确认 action run 成功,不再出现 `refusing to fetch into branch` 错误\n- [ ] 在本仓库分支的 pr / issue 上 `@claude`,确认正常路径不退化\n- [ ] 若有第二个 fork pr head ref name 与 base 不同名,确认仍正常工作"}, "file": {"name": "git_provider.py", "path": "/app/pr_agent/git_providers/git_provider.py"}, "function": "get_user_description", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 225, "message": "Existing description", "module": "git_provider", "name": "pr_agent.git_providers.git_provider", "process": {"id": 7, "name": "MainProcess"}, "thread": {"id": 140562690771840, "name": "MainThread"}, "time": {"repr": "2026-05-17 02:39:19.220621+00:00", "timestamp": 1778985559.220621}}}