fix: use unique local branch names for PR checkout to avoid conflicts (#931)

The previous implementation used the PR's original branch name when
fetching, which could conflict with existing local or remote branches
of the same name. This caused checkout failures for PRs with common
branch names like 'main' or 'feature/xyz'.

Changes:
- Use 'pr-{number}' format for local branch names (e.g., pr-385)
- Preserve original branch name for logging purposes
- Add detailed logging showing original -> local branch mapping

This ensures uniqueness since PR numbers are unique per repository,
while maintaining support for both same-repo and fork PRs via
GitHub's pull/{number}/head refs.

Fixes the issue introduced in #851 where fork PR support was added.

Co-authored-by: Yi-Cheng Wang <yicheng.wang@heph-ai.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Yi-Cheng Wang 2026-02-12 11:30:25 +08:00 committed by GitHub
parent 8c383c5de3
commit f669191d7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -151,7 +151,10 @@ export async function setupBranch(
// Handle open PR: Checkout the PR branch
console.log("This is an open PR, checking out PR branch...");
const branchName = prData.headRefName;
const originalBranchName = prData.headRefName;
// Use unique local branch name to avoid conflicts with existing branches
// Format: pr-{number} ensures uniqueness since PR numbers are unique per repo
const localBranchName = `pr-${entityNumber}`;
// Determine optimal fetch depth based on PR commit count, with a minimum of 20
const commitCount = prData.commits.totalCount;
@ -160,22 +163,28 @@ export async function setupBranch(
console.log(
`PR #${entityNumber}: ${commitCount} commits, using fetch depth ${fetchDepth}`,
);
console.log(
`Fetching PR branch '${originalBranchName}' as local branch '${localBranchName}'`,
);
// Validate branch names before use to prevent command injection
validateBranchName(branchName);
validateBranchName(localBranchName);
// Execute git commands to checkout PR branch (dynamic depth based on PR size)
// Using execFileSync instead of shell template literals for security
// Use GitHub's PR ref which works for both same-repo and fork PRs
// The local branch name uses pr-{number} format to ensure uniqueness
execGit([
"fetch",
"origin",
`--depth=${fetchDepth}`,
`pull/${entityNumber}/head:${branchName}`,
`pull/${entityNumber}/head:${localBranchName}`,
]);
execGit(["checkout", branchName, "--"]);
execGit(["checkout", localBranchName, "--"]);
console.log(`Successfully checked out PR branch for PR #${entityNumber}`);
console.log(
`Successfully checked out PR #${entityNumber} as local branch '${localBranchName}'`,
);
// For open PRs, we need to get the base branch of the PR
const baseBranch = prData.baseRefName;
@ -183,7 +192,7 @@ export async function setupBranch(
return {
baseBranch,
currentBranch: branchName,
currentBranch: localBranchName,
};
}
}