Skip to content

Conversation

@SuperComboGamer
Copy link
Collaborator

@SuperComboGamer SuperComboGamer commented Jan 6, 2026

  • Updated multiple route handlers to use 'git symbolic-ref --short HEAD' instead of 'git rev-parse --abbrev-ref HEAD' for retrieving the current branch name, improving consistency and clarity in branch management across the application.

Summary by CodeRabbit

  • Refactor
    • Updated branch detection method across worktree operations (checkout, commit, PR creation, delete, info, list branches, merge, pull, push, and switch). This improves accuracy of branch identification in standard Git workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

- Updated multiple route handlers to use 'git symbolic-ref --short HEAD' instead of 'git rev-parse --abbrev-ref HEAD' for retrieving the current branch name, improving consistency and clarity in branch management across the application.
@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Replaced the Git command for retrieving the current branch name across ten worktree routes. All instances of git rev-parse --abbrev-ref HEAD are now git symbolic-ref --short HEAD, maintaining identical downstream logic in each file.

Changes

Cohort / File(s) Summary
Worktree Route Git Command Updates
apps/server/src/routes/worktree/routes/checkout-branch.ts, commit.ts, create-pr.ts, delete.ts, info.ts, list-branches.ts, merge.ts, pull.ts, push.ts, switch-branch.ts
Unified replacement of branch detection command from git rev-parse --abbrev-ref HEAD to git symbolic-ref --short HEAD across all worktree operation routes. Impacts behavior in detached HEAD scenarios where the new command may fail or return different output compared to the previous command.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A hop through the branches, so swift and so clean,
From rev-parse to symbolic, we've switched our routine,
Ten files now agree on the path that we take,
While HEAD must stay tethered, for goodness's sake!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: replace git command for branch retrieval' clearly and concisely summarizes the main change across all modified files—replacing one Git command with another for branch name retrieval.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @SuperComboGamer, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the application's approach to retrieving the current Git branch name. By standardizing the command used from git rev-parse --abbrev-ref HEAD to git symbolic-ref --short HEAD across several server-side route handlers, the change improves the overall consistency and clarity of branch management within the application. This ensures a more uniform and explicit method for identifying the active branch in various worktree-related operations.

Highlights

  • Git Command Refactoring: The git rev-parse --abbrev-ref HEAD command has been replaced with git symbolic-ref --short HEAD for retrieving the current branch name.
  • Improved Consistency: This change aims to enhance consistency and clarity in how branch names are managed across various parts of the application.
  • Affected Modules: The update has been applied to multiple route handlers within the apps/server/src/routes/worktree/routes/ directory, including checkout-branch.ts, commit.ts, create-pr.ts, delete.ts, info.ts, list-branches.ts, merge.ts, pull.ts, push.ts, and switch-branch.ts.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request consistently refactors multiple route handlers to use git symbolic-ref --short HEAD instead of git rev-parse --abbrev-ref HEAD for retrieving the current branch name. This is a positive change that improves consistency and robustness, as symbolic-ref is generally the more appropriate command for this purpose and fails explicitly in detached HEAD states. The change is well-implemented across all relevant files. I have one minor suggestion to remove some unnecessary code.


// Get current branch
const { stdout: currentBranch } = await execAsync('git rev-parse --abbrev-ref HEAD', {
const { stdout: currentBranch } = await execAsync('git symbolic-ref --short HEAD', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The currentBranch variable is not used within this function. This execAsync call to get the branch name is unnecessary. Consider removing this block of code (lines 37-40) to improve performance and code clarity.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Fix all issues with AI Agents
In @apps/server/src/routes/worktree/routes/checkout-branch.ts:
- Around line 50-53: The git symbolic-ref call can throw in detached HEAD state;
wrap the execAsync('git symbolic-ref --short HEAD', { cwd: worktreePath })
invocation used to compute currentBranch in checkout-branch.ts in a try/catch
and, on failure, call execAsync('git rev-parse HEAD', { cwd: worktreePath }) to
set previousBranch/currentBranch to the commit SHA (or alternatively return a
clear 4xx error that explains the detached HEAD) so branch creation via checkout
(e.g., git checkout -b) still works and you avoid unhandled 500s; update the
variables currentBranch/currentBranchOutput/previousBranch accordingly and apply
the same pattern to other handlers that use git symbolic-ref.

In @apps/server/src/routes/worktree/routes/create-pr.ts:
- Line 46: The current use of execAsync('git symbolic-ref --short HEAD', ...)
assigns to branchOutput but doesn't explicitly detect a detached HEAD; when that
command fails the outer catch returns a generic 500 with raw git stderr. Update
the handler to explicitly validate the current HEAD: run the branch lookup (or
use 'git rev-parse --abbrev-ref HEAD') and if the result is 'HEAD' or empty (or
the command exits non-zero) return a clear 400/422 response like "repository is
in a detached HEAD; worktrees must be created from a branch", instead of letting
the outer try-catch return a generic 500; factor this logic into a shared helper
(e.g., getCurrentBranchOrThrow or validateBranchOnBranch) so the same explicit
detached-HEAD check can be reused across the other worktree route files that use
branchOutput.

In @apps/server/src/routes/worktree/routes/list-branches.ts:
- Around line 37-40: The current code calls execAsync('git symbolic-ref --short
HEAD') and assumes success; wrap that call (the section producing
currentBranchOutput/currentBranch) in a try/catch, and on failure call
execAsync('git rev-parse --short HEAD') to get the commit SHA (trimmed) or set
currentBranch to a sentinel like "HEAD (detached)"; ensure you reuse execAsync
and assign to currentBranch so downstream logic still works and keep errors
non-fatal for the list-branches endpoint.

In @apps/server/src/routes/worktree/routes/merge.ts:
- Around line 38-40: Remove the unused currentBranch retrieval that calls
execAsync('git symbolic-ref --short HEAD', { cwd: projectPath }) — this can
throw on detached HEAD and its result is never used; delete the const { stdout:
currentBranch } = await execAsync(...) statement (and any immediate unused
variable) from merge.ts so the merge logic no longer executes the git
symbolic-ref command or relies on currentBranch.

In @apps/server/src/routes/worktree/routes/switch-branch.ts:
- Around line 90-93: The code assumes `git symbolic-ref --short HEAD` always
succeeds; wrap the execAsync call in try/catch and handle detached HEADs by
falling back to obtaining the current commit (e.g., run `git rev-parse --short
HEAD` via execAsync) or set previousBranch to a stable sentinel like
`HEAD@{detached}` so downstream logic can still switch branches; update
references to previousBranch (the variable set from currentBranchOutput) so they
tolerate the fallback value and ensure errors are only thrown for unexpected
failures (rethrow other exec errors).
🧹 Nitpick comments (1)
apps/server/src/routes/worktree/routes/info.ts (1)

34-34: Use git branch --show-current for consistency with list.ts and modern Git practices.

This worktree route currently uses git symbolic-ref --short HEAD, but list.ts already uses git branch --show-current (available since Git 2.22.0). The latter is purpose-built for this use case, returns an empty string gracefully in detached HEAD scenarios rather than throwing an error, and simplifies error handling. Consolidating all worktree route branch retrieval on git branch --show-current would improve consistency across the codebase.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a6a83b and 6c669fb.

📒 Files selected for processing (10)
  • apps/server/src/routes/worktree/routes/checkout-branch.ts
  • apps/server/src/routes/worktree/routes/commit.ts
  • apps/server/src/routes/worktree/routes/create-pr.ts
  • apps/server/src/routes/worktree/routes/delete.ts
  • apps/server/src/routes/worktree/routes/info.ts
  • apps/server/src/routes/worktree/routes/list-branches.ts
  • apps/server/src/routes/worktree/routes/merge.ts
  • apps/server/src/routes/worktree/routes/pull.ts
  • apps/server/src/routes/worktree/routes/push.ts
  • apps/server/src/routes/worktree/routes/switch-branch.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always import from shared packages (@automaker/*), never from old relative paths

Files:

  • apps/server/src/routes/worktree/routes/switch-branch.ts
  • apps/server/src/routes/worktree/routes/delete.ts
  • apps/server/src/routes/worktree/routes/merge.ts
  • apps/server/src/routes/worktree/routes/list-branches.ts
  • apps/server/src/routes/worktree/routes/create-pr.ts
  • apps/server/src/routes/worktree/routes/push.ts
  • apps/server/src/routes/worktree/routes/checkout-branch.ts
  • apps/server/src/routes/worktree/routes/pull.ts
  • apps/server/src/routes/worktree/routes/info.ts
  • apps/server/src/routes/worktree/routes/commit.ts
apps/server/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use createEventEmitter() from lib/events.ts for all server operations to emit events that stream to frontend via WebSocket

Files:

  • apps/server/src/routes/worktree/routes/switch-branch.ts
  • apps/server/src/routes/worktree/routes/delete.ts
  • apps/server/src/routes/worktree/routes/merge.ts
  • apps/server/src/routes/worktree/routes/list-branches.ts
  • apps/server/src/routes/worktree/routes/create-pr.ts
  • apps/server/src/routes/worktree/routes/push.ts
  • apps/server/src/routes/worktree/routes/checkout-branch.ts
  • apps/server/src/routes/worktree/routes/pull.ts
  • apps/server/src/routes/worktree/routes/info.ts
  • apps/server/src/routes/worktree/routes/commit.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use resolveModelString() from @automaker/model-resolver to convert model aliases (haiku, sonnet, opus) to full model names

Files:

  • apps/server/src/routes/worktree/routes/switch-branch.ts
  • apps/server/src/routes/worktree/routes/delete.ts
  • apps/server/src/routes/worktree/routes/merge.ts
  • apps/server/src/routes/worktree/routes/list-branches.ts
  • apps/server/src/routes/worktree/routes/create-pr.ts
  • apps/server/src/routes/worktree/routes/push.ts
  • apps/server/src/routes/worktree/routes/checkout-branch.ts
  • apps/server/src/routes/worktree/routes/pull.ts
  • apps/server/src/routes/worktree/routes/info.ts
  • apps/server/src/routes/worktree/routes/commit.ts
🧠 Learnings (1)
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Each feature executes in an isolated git worktree created via automaker/git-utils to protect the main branch during AI agent execution

Applied to files:

  • apps/server/src/routes/worktree/routes/merge.ts
  • apps/server/src/routes/worktree/routes/info.ts
🧬 Code graph analysis (10)
apps/server/src/routes/worktree/routes/switch-branch.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/delete.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/merge.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/list-branches.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/create-pr.ts (2)
apps/server/src/routes/github/routes/common.ts (1)
  • execAsync (11-11)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/push.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/checkout-branch.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/pull.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/info.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
apps/server/src/routes/worktree/routes/commit.ts (1)
apps/server/src/routes/worktree/common.ts (1)
  • execAsync (13-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (2)
apps/server/src/routes/worktree/routes/delete.ts (1)

41-47: Proper error handling for detached HEAD scenarios.

The command change is safely wrapped in a try-catch block. When a repo is in a detached HEAD state, git symbolic-ref --short HEAD will fail with "fatal: ref HEAD is not a symbolic ref", so the fallback to null appropriately handles this edge case.

apps/server/src/routes/worktree/routes/info.ts (1)

34-44: Proper error handling for detached HEAD scenarios.

The command is appropriately wrapped in error handling that falls back to null values when the branch name cannot be determined, which is the correct behavior for an info endpoint.

Comment on lines +50 to 53
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const currentBranch = currentBranchOutput.trim();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

wc -l apps/server/src/routes/worktree/routes/checkout-branch.ts

Repository: AutoMaker-Org/automaker

Length of output: 190


🏁 Script executed:

cat -n apps/server/src/routes/worktree/routes/checkout-branch.ts

Repository: AutoMaker-Org/automaker

Length of output: 3121


🏁 Script executed:

rg -n 'detached|symbolic-ref|previousBranch' apps/server/src/routes/worktree/ --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 1996


🏁 Script executed:

# Search for tests related to checkout-branch or detached HEAD
fd -t f '*.test.ts' -o '*.spec.ts' apps/server | xargs rg -l 'checkout.*branch|detached' 2>/dev/null || echo "No matching test files found"

Repository: AutoMaker-Org/automaker

Length of output: 700


🏁 Script executed:

# Check the middleware mentioned in the file (requireValidWorktree)
rg -n 'requireValidWorktree' apps/server/src/routes/worktree/ --type=ts -A 5

Repository: AutoMaker-Org/automaker

Length of output: 5583


🏁 Script executed:

# Check what happens with git symbolic-ref on detached HEAD
# Look at the actual error message and understand the implications
rg -n 'symbolic-ref' apps/server/src/ --type=ts | head -20

Repository: AutoMaker-Org/automaker

Length of output: 1503


🏁 Script executed:

# Check if there's any documentation or TODOs about this
rg -n 'TODO|FIXME|detached|HEAD' apps/server/src/routes/worktree/ --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 3028


🏁 Script executed:

cat -n apps/server/src/routes/worktree/middleware.ts | head -100

Repository: AutoMaker-Org/automaker

Length of output: 2746


🏁 Script executed:

# Check what the middleware validation does
rg -n 'isGitRepo\|hasCommits' apps/server/src/routes/worktree/ --type=ts -B 2 -A 5

Repository: AutoMaker-Org/automaker

Length of output: 49


🏁 Script executed:

# Check if there are any existing tests for worktree operations
find apps/server -type f -name '*.test.*' -o -name '*.spec.*' | head -10

Repository: AutoMaker-Org/automaker

Length of output: 613


🏁 Script executed:

cat -n apps/server/tests/integration/routes/worktree/create.integration.test.ts | head -150

Repository: AutoMaker-Org/automaker

Length of output: 2489


🏁 Script executed:

# Check if there are any tests for checkout-branch, switch-branch, or detached HEAD scenarios
rg -n 'checkout.*branch|switch.*branch|detached' apps/server/tests/ --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 49


🏁 Script executed:

# Understand what git symbolic-ref error looks like and what the implications are
# Let's check the common.ts to see how errors are handled
cat -n apps/server/src/routes/worktree/common.ts

Repository: AutoMaker-Org/automaker

Length of output: 7421


🏁 Script executed:

# Verify what error message git symbolic-ref produces in detached HEAD
# Check if there are any related issues or PRs mentioned in the codebase
rg -n 'detached.*HEAD|symbolic.*ref' docs/ CONTRIBUTING.md README.md 2>/dev/null || echo "No docs mention detached HEAD"

Repository: AutoMaker-Org/automaker

Length of output: 96


🏁 Script executed:

# Confirm the systematic nature by checking all files that use symbolic-ref without error handling
rg -l 'symbolic-ref.*HEAD' apps/server/src/routes/worktree/routes/ --type=ts | wc -l

Repository: AutoMaker-Org/automaker

Length of output: 69


Handle detached HEAD state across symbolic-ref calls.

The git symbolic-ref --short HEAD call will fail when the repository is in a detached HEAD state, even though the repository passes all middleware validation (which only checks that commits exist via git rev-parse --verify HEAD). This affects 10 files in the worktree routes and causes ungraceful 500 errors with generic messages instead of informative feedback.

For checkout-branch.ts specifically: creating a branch from detached HEAD is a valid Git operation (git checkout -b works fine), but retrieving the previous branch state fails. Consider wrapping the git symbolic-ref call in a try-catch to either:

  • Set previousBranch to the commit SHA (via git rev-parse HEAD) when detached
  • Return a clear error message explaining detached HEAD state

This pattern should be addressed consistently across all symbolic-ref calls in the worktree route handlers.

🤖 Prompt for AI Agents
In @apps/server/src/routes/worktree/routes/checkout-branch.ts around lines
50-53, The git symbolic-ref call can throw in detached HEAD state; wrap the
execAsync('git symbolic-ref --short HEAD', { cwd: worktreePath }) invocation
used to compute currentBranch in checkout-branch.ts in a try/catch and, on
failure, call execAsync('git rev-parse HEAD', { cwd: worktreePath }) to set
previousBranch/currentBranch to the commit SHA (or alternatively return a clear
4xx error that explains the detached HEAD) so branch creation via checkout
(e.g., git checkout -b) still works and you avoid unhandled 500s; update the
variables currentBranch/currentBranchOutput/previousBranch accordingly and apply
the same pattern to other handlers that use git symbolic-ref.

Comment on lines +62 to 65
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const branchName = branchOutput.trim();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing error handling for detached HEAD state.

In a detached HEAD state, git symbolic-ref --short HEAD will fail with an error, causing the entire handler to return a 500 error even though the commit operation itself (line 51) succeeded. This could confuse users and lose context about the successful commit.

🔎 Proposed fix to add error handling
-      // Get branch name
-      const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
-        cwd: worktreePath,
-      });
-      const branchName = branchOutput.trim();
+      // Get branch name (may be null in detached HEAD state)
+      let branchName: string | null = null;
+      try {
+        const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
+          cwd: worktreePath,
+        });
+        branchName = branchOutput.trim();
+      } catch {
+        // Detached HEAD state - branch name unavailable
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const branchName = branchOutput.trim();
// Get branch name (may be null in detached HEAD state)
let branchName: string | null = null;
try {
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
branchName = branchOutput.trim();
} catch {
// Detached HEAD state - branch name unavailable
}


// Get current branch name
const { stdout: branchOutput } = await execAsync('git rev-parse --abbrev-ref HEAD', {
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file and context around line 46
cat -n apps/server/src/routes/worktree/routes/create-pr.ts | sed -n '30,60p'

Repository: AutoMaker-Org/automaker

Length of output: 1204


🏁 Script executed:

# Run the provided search for detached HEAD handling
rg -n -C3 'detached.HEAD|HEAD detached' --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 49


🏁 Script executed:

# Also search for git symbolic-ref usage in the codebase
rg -n 'git symbolic-ref' --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 1503


🏁 Script executed:

# Search for error handling around the git command in the file
cat -n apps/server/src/routes/worktree/routes/create-pr.ts | head -100

Repository: AutoMaker-Org/automaker

Length of output: 4097


🏁 Script executed:

# View the rest of the create-pr.ts file to see error handling
cat -n apps/server/src/routes/worktree/routes/create-pr.ts | sed -n '100,150p'

Repository: AutoMaker-Org/automaker

Length of output: 2128


🏁 Script executed:

# Check the common.ts to understand execAsync error behavior
cat -n apps/server/src/routes/worktree/routes/common.ts | head -80

Repository: AutoMaker-Org/automaker

Length of output: 147


🏁 Script executed:

# Check if there's worktree initialization that ensures non-detached HEAD
rg -n -C5 'worktree create|worktree add' --type=ts

Repository: AutoMaker-Org/automaker

Length of output: 4737


🏁 Script executed:

# Find common.ts in the worktree routes
find apps/server/src/routes/worktree -name "common.ts"

Repository: AutoMaker-Org/automaker

Length of output: 108


🏁 Script executed:

# Check the error handling wrapper that execAsync would trigger
cat -n apps/server/src/routes/worktree/common.ts | head -100

Repository: AutoMaker-Org/automaker

Length of output: 4136


🏁 Script executed:

# Look at the try-catch block in create-pr.ts to see what happens when execAsync throws
cat -n apps/server/src/routes/worktree/routes/create-pr.ts | sed -n '150,200p'

Repository: AutoMaker-Org/automaker

Length of output: 2516


🏁 Script executed:

# Check the final catch block of the create-pr.ts handler to see generic error handling
cat -n apps/server/src/routes/worktree/routes/create-pr.ts | tail -50

Repository: AutoMaker-Org/automaker

Length of output: 2008


Add explicit detached HEAD error handling.

The git symbolic-ref --short HEAD command fails in detached HEAD state and lacks explicit error handling. While the outer try-catch (line 397) catches this failure, it returns a generic 500 error with raw git stderr. Since worktrees are created on branches and this pattern is used consistently across 10 worktree route files, either:

  1. Add explicit detached HEAD validation that returns a clear error message, or
  2. Document the assumption that worktrees are always on branches (and validate accordingly)

The current implicit error handling via the generic catch block is insufficient for user guidance.

🤖 Prompt for AI Agents
In @apps/server/src/routes/worktree/routes/create-pr.ts around line 46, The
current use of execAsync('git symbolic-ref --short HEAD', ...) assigns to
branchOutput but doesn't explicitly detect a detached HEAD; when that command
fails the outer catch returns a generic 500 with raw git stderr. Update the
handler to explicitly validate the current HEAD: run the branch lookup (or use
'git rev-parse --abbrev-ref HEAD') and if the result is 'HEAD' or empty (or the
command exits non-zero) return a clear 400/422 response like "repository is in a
detached HEAD; worktrees must be created from a branch", instead of letting the
outer try-catch return a generic 500; factor this logic into a shared helper
(e.g., getCurrentBranchOrThrow or validateBranchOnBranch) so the same explicit
detached-HEAD check can be reused across the other worktree route files that use
branchOutput.

Comment on lines +37 to 40
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const currentBranch = currentBranchOutput.trim();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine the relevant lines
if [ -f "apps/server/src/routes/worktree/routes/list-branches.ts" ]; then
  echo "=== File exists, showing context around lines 37-40 ==="
  wc -l apps/server/src/routes/worktree/routes/list-branches.ts
  echo ""
  echo "=== Lines 30-50 ==="
  sed -n '30,50p' apps/server/src/routes/worktree/routes/list-branches.ts
else
  echo "File not found at specified path"
fi

Repository: AutoMaker-Org/automaker

Length of output: 938


🏁 Script executed:

# Search for similar git symbolic-ref patterns in the codebase
echo "=== Searching for git symbolic-ref usage ==="
rg "git symbolic-ref" --type ts --type tsx -n

Repository: AutoMaker-Org/automaker

Length of output: 156


🏁 Script executed:

# Search for git rev-parse usage to understand common patterns
echo "=== Searching for git rev-parse usage ==="
rg "git rev-parse" --type ts --type tsx -n -A 2

Repository: AutoMaker-Org/automaker

Length of output: 153


🏁 Script executed:

# Search for git symbolic-ref and git rev-parse with correct syntax
echo "=== Searching for git symbolic-ref usage ==="
rg "git symbolic-ref" --type ts -n

echo ""
echo "=== Searching for git rev-parse usage ==="
rg "git rev-parse" --type ts -n -A 2

Repository: AutoMaker-Org/automaker

Length of output: 4748


🏁 Script executed:

# Examine the full function to understand its purpose and callers
echo "=== Full function context (lines 1-60) ==="
sed -n '1,60p' apps/server/src/routes/worktree/routes/list-branches.ts

Repository: AutoMaker-Org/automaker

Length of output: 1977


🏁 Script executed:

# Check if there are error handlers elsewhere in the codebase for execAsync
echo "=== Searching for execAsync error handling patterns ==="
rg "execAsync" --type ts -A 3 | head -50

Repository: AutoMaker-Org/automaker

Length of output: 2952


Add graceful handling for detached HEAD state.

The git symbolic-ref --short HEAD command fails when the worktree is in a detached HEAD state, causing the entire list-branches endpoint to fail. For a read-only list operation, this significantly degrades UX. Catch the error and fall back to git rev-parse --short HEAD to display the commit SHA, or use a sentinel value like "HEAD (detached)".

Proposed fix
-      const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
-        cwd: worktreePath,
-      });
-      const currentBranch = currentBranchOutput.trim();
+      let currentBranch: string;
+      try {
+        const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
+          cwd: worktreePath,
+        });
+        currentBranch = currentBranchOutput.trim();
+      } catch {
+        // Detached HEAD state - use commit SHA
+        const { stdout: commitSha } = await execAsync('git rev-parse --short HEAD', {
+          cwd: worktreePath,
+        });
+        currentBranch = `HEAD (detached at ${commitSha.trim()})`;
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const currentBranch = currentBranchOutput.trim();
let currentBranch: string;
try {
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
currentBranch = currentBranchOutput.trim();
} catch {
// Detached HEAD state - use commit SHA
const { stdout: commitSha } = await execAsync('git rev-parse --short HEAD', {
cwd: worktreePath,
});
currentBranch = `HEAD (detached at ${commitSha.trim()})`;
}
🤖 Prompt for AI Agents
In @apps/server/src/routes/worktree/routes/list-branches.ts around lines 37-40,
The current code calls execAsync('git symbolic-ref --short HEAD') and assumes
success; wrap that call (the section producing
currentBranchOutput/currentBranch) in a try/catch, and on failure call
execAsync('git rev-parse --short HEAD') to get the commit SHA (trimmed) or set
currentBranch to a sentinel like "HEAD (detached)"; ensure you reuse execAsync
and assign to currentBranch so downstream logic still works and keep errors
non-fatal for the list-branches endpoint.

Comment on lines +38 to 40
const { stdout: currentBranch } = await execAsync('git symbolic-ref --short HEAD', {
cwd: projectPath,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/server/src/routes/worktree/routes/merge.ts

Repository: AutoMaker-Org/automaker

Length of output: 2860


Remove unused currentBranch variable—the git symbolic-ref command will fail in detached HEAD state and is never used.

Lines 38-40 fetch the current branch name but never reference it in the merge logic. The command will throw an error if the repository is in a detached HEAD state, with no error handling. Delete these lines entirely since the merge operation does not depend on knowing the current branch.

🤖 Prompt for AI Agents
In @apps/server/src/routes/worktree/routes/merge.ts around lines 38-40, Remove
the unused currentBranch retrieval that calls execAsync('git symbolic-ref
--short HEAD', { cwd: projectPath }) — this can throw on detached HEAD and its
result is never used; delete the const { stdout: currentBranch } = await
execAsync(...) statement (and any immediate unused variable) from merge.ts so
the merge logic no longer executes the git symbolic-ref command or relies on
currentBranch.

Comment on lines +31 to 34
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const branchName = branchOutput.trim();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing error handling for detached HEAD state.

When a repo is in a detached HEAD state, git symbolic-ref --short HEAD will fail, causing the handler to return a generic 500 error rather than a meaningful message about the detached HEAD state.

🔎 Proposed fix to add error handling
-      // Get current branch name
-      const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
-        cwd: worktreePath,
-      });
-      const branchName = branchOutput.trim();
+      // Get current branch name
+      let branchName: string;
+      try {
+        const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
+          cwd: worktreePath,
+        });
+        branchName = branchOutput.trim();
+      } catch {
+        res.status(400).json({
+          success: false,
+          error: 'Cannot pull: worktree is in detached HEAD state',
+        });
+        return;
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const branchName = branchOutput.trim();
// Get current branch name
let branchName: string;
try {
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
branchName = branchOutput.trim();
} catch {
res.status(400).json({
success: false,
error: 'Cannot pull: worktree is in detached HEAD state',
});
return;
}


// Get branch name
const { stdout: branchOutput } = await execAsync('git rev-parse --abbrev-ref HEAD', {
const { stdout: branchOutput } = await execAsync('git symbolic-ref --short HEAD', {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/server/src/routes/worktree/routes/push.ts | head -80

Repository: AutoMaker-Org/automaker

Length of output: 2256


🏁 Script executed:

#!/bin/bash
# Create a temporary test repository
TEST_DIR=$(mktemp -d)
cd "$TEST_DIR"
git init

# Create initial commit
echo "test" > file.txt
git add file.txt
git commit -m "initial"

# Get the commit hash
COMMIT_HASH=$(git rev-parse HEAD)

# Test 1: Normal branch state
echo "=== Test 1: Normal branch state ==="
echo "git symbolic-ref --short HEAD:"
git symbolic-ref --short HEAD
echo "git rev-parse --abbrev-ref HEAD:"
git rev-parse --abbrev-ref HEAD

# Test 2: Detached HEAD state
echo ""
echo "=== Test 2: Detached HEAD state ==="
git checkout "$COMMIT_HASH"

echo "git symbolic-ref --short HEAD:"
git symbolic-ref --short HEAD 2>&1 || echo "FAILED with exit code: $?"

echo "git rev-parse --abbrev-ref HEAD:"
git rev-parse --abbrev-ref HEAD 2>&1

# Cleanup
cd /
rm -rf "$TEST_DIR"

Repository: AutoMaker-Org/automaker

Length of output: 1868


🏁 Script executed:

#!/bin/bash
# Create a temporary test repository
TEST_DIR=$(mktemp -d)
cd "$TEST_DIR"
git init

# Configure git
git config user.email "test@example.com"
git config user.name "Test User"

# Create initial commit
echo "test" > file.txt
git add file.txt
git commit -m "initial"

# Get the commit hash
COMMIT_HASH=$(git rev-parse HEAD)

# Test 1: Normal branch state
echo "=== Test 1: Normal branch state ==="
echo "git symbolic-ref --short HEAD:"
git symbolic-ref --short HEAD
echo "Exit code: $?"
echo ""
echo "git rev-parse --abbrev-ref HEAD:"
git rev-parse --abbrev-ref HEAD
echo "Exit code: $?"

# Test 2: Detached HEAD state
echo ""
echo "=== Test 2: Detached HEAD state ==="
echo "Checking out commit: $COMMIT_HASH"
git checkout "$COMMIT_HASH"
echo ""

echo "Verifying detached HEAD:"
git symbolic-ref -q HEAD && echo "Still on branch" || echo "In detached HEAD state"
echo ""

echo "git symbolic-ref --short HEAD:"
git symbolic-ref --short HEAD 2>&1
echo "Exit code: $?"
echo ""

echo "git rev-parse --abbrev-ref HEAD:"
git rev-parse --abbrev-ref HEAD 2>&1
echo "Exit code: $?"

# Cleanup
cd /
rm -rf "$TEST_DIR"

Repository: AutoMaker-Org/automaker

Length of output: 1829


Add error handling for detached HEAD state.

git symbolic-ref --short HEAD fails with exit code 128 in detached HEAD state (error: "ref HEAD is not a symbolic ref"). Since detached HEAD is a possible state in git worktrees, add specific error handling to gracefully inform the user instead of returning a generic 500 error.

Note: git rev-parse --abbrev-ref HEAD returns the string "HEAD" in detached state, not a commit SHA, so it's not a suitable alternative for this use case.

Comment on lines +90 to 93
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const previousBranch = currentBranchOutput.trim();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing error handling for detached HEAD state.

When in a detached HEAD state, git symbolic-ref --short HEAD will fail, causing a generic 500 error. However, switching branches from a detached HEAD is a valid operation that should be supported with better error handling.

🔎 Proposed fix to add error handling
-      // Get current branch
-      const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
-        cwd: worktreePath,
-      });
-      const previousBranch = currentBranchOutput.trim();
+      // Get current branch (may be in detached HEAD state)
+      let previousBranch: string;
+      try {
+        const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
+          cwd: worktreePath,
+        });
+        previousBranch = currentBranchOutput.trim();
+      } catch {
+        previousBranch = 'detached HEAD';
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
const previousBranch = currentBranchOutput.trim();
// Get current branch (may be in detached HEAD state)
let previousBranch: string;
try {
const { stdout: currentBranchOutput } = await execAsync('git symbolic-ref --short HEAD', {
cwd: worktreePath,
});
previousBranch = currentBranchOutput.trim();
} catch {
previousBranch = 'detached HEAD';
}
🤖 Prompt for AI Agents
In @apps/server/src/routes/worktree/routes/switch-branch.ts around lines 90-93,
The code assumes `git symbolic-ref --short HEAD` always succeeds; wrap the
execAsync call in try/catch and handle detached HEADs by falling back to
obtaining the current commit (e.g., run `git rev-parse --short HEAD` via
execAsync) or set previousBranch to a stable sentinel like `HEAD@{detached}` so
downstream logic can still switch branches; update references to previousBranch
(the variable set from currentBranchOutput) so they tolerate the fallback value
and ensure errors are only thrown for unexpected failures (rethrow other exec
errors).

@webdevcody webdevcody closed this Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants