Skip to content

Commit 61e53d4

Browse files
committed
Fix SSHRuntime trunk branch handling
- Create local tracking branches for all remote refs after clone - This ensures branch names work directly without needing 'origin/' prefix - Simplify checkout command to use branch names directly - Add debug logging to help diagnose issues The issue was that after git clone from bundle, all branches exist as origin/* remote refs. When we later remove the origin remote, these refs disappear. By creating local tracking branches first, we ensure the branch names are available for checkout operations, fixing the trunk branch parameter handling.
1 parent fd98c61 commit 61e53d4

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

src/runtime/SSHRuntime.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,21 @@ export class SSHRuntime implements Runtime {
480480
throw new Error(`Failed to clone repository: ${cloneStderr || cloneStdout}`);
481481
}
482482

483-
// Step 4: Update origin remote if we have an origin URL
483+
// Step 4: Create local tracking branches for all remote branches
484+
// This ensures that branch names like "custom-trunk" can be used directly
485+
// in git checkout commands, rather than needing "origin/custom-trunk"
486+
initLogger.logStep(`Creating local tracking branches...`);
487+
const createTrackingBranchesStream = await this.exec(
488+
`cd ${cloneDestPath} && for branch in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin/ | grep -v 'origin/HEAD'); do localname=\${branch#origin/}; git show-ref --verify --quiet refs/heads/$localname || git branch $localname $branch; done`,
489+
{
490+
cwd: "~",
491+
timeout: 30,
492+
}
493+
);
494+
await createTrackingBranchesStream.exitCode;
495+
// Don't fail if this fails - some branches may already exist
496+
497+
// Step 5: Update origin remote if we have an origin URL
484498
if (originUrl) {
485499
initLogger.logStep(`Setting origin remote to ${originUrl}...`);
486500
const setOriginStream = await this.exec(
@@ -689,10 +703,24 @@ export class SSHRuntime implements Runtime {
689703

690704
// 2. Checkout branch remotely
691705
// If branch exists locally, check it out; otherwise create it from the specified trunk branch
692-
// Note: After git clone from bundle, branches exist as origin/* refs, so we need to check both
693-
// local branch and origin/branch when creating the new branch
706+
// Note: We've already created local branches for all remote refs in syncProjectToRemote
694707
initLogger.logStep(`Checking out branch: ${branchName}`);
695-
const checkoutCmd = `(git checkout ${shescape.quote(branchName)} 2>/dev/null || git checkout -b ${shescape.quote(branchName)} origin/${shescape.quote(trunkBranch)} 2>/dev/null || git checkout -b ${shescape.quote(branchName)} ${shescape.quote(trunkBranch)})`;
708+
709+
// DEBUG: Log git state after clone
710+
initLogger.logStep(`[DEBUG] Inspecting git state after clone...`);
711+
const debugStream = await this.exec(
712+
`echo "=== Current branch ===" && git branch && echo "=== All branches ===" && git branch -a && echo "=== HEAD ===" && git rev-parse HEAD && echo "=== Files ===" && ls -la`,
713+
{ cwd: workspacePath, timeout: 30 }
714+
);
715+
const [debugOut] = await Promise.all([
716+
streamToString(debugStream.stdout),
717+
debugStream.exitCode,
718+
]);
719+
initLogger.logStdout(debugOut);
720+
721+
// Try to checkout existing branch, or create new branch from trunk
722+
// Since we've created local branches for all remote refs, we can use branch names directly
723+
const checkoutCmd = `git checkout ${shescape.quote(branchName)} 2>/dev/null || git checkout -b ${shescape.quote(branchName)} ${shescape.quote(trunkBranch)}`;
696724

697725
const checkoutStream = await this.exec(checkoutCmd, {
698726
cwd: workspacePath, // Use the full workspace path for git operations
@@ -716,6 +744,18 @@ export class SSHRuntime implements Runtime {
716744
}
717745
initLogger.logStep("Branch checked out successfully");
718746

747+
// DEBUG: Log git state after checkout
748+
initLogger.logStep(`[DEBUG] Inspecting git state after checkout...`);
749+
const debugStream2 = await this.exec(
750+
`echo "=== Current branch ===" && git branch && echo "=== HEAD ===" && git rev-parse HEAD && echo "=== Files ===" && ls -la && echo "=== Last commits ===" && git log --oneline -5`,
751+
{ cwd: workspacePath, timeout: 30 }
752+
);
753+
const [debugOut2] = await Promise.all([
754+
streamToString(debugStream2.stdout),
755+
debugStream2.exitCode,
756+
]);
757+
initLogger.logStdout(debugOut2);
758+
719759
// 3. Run .cmux/init hook if it exists
720760
// Note: runInitHook calls logComplete() internally if hook exists
721761
const hookExists = await checkInitHookExists(projectPath);

0 commit comments

Comments
 (0)